challenge 文字列型日時ののN秒後時間取得

日時を表す文字列と時間(秒)を受け取り
指定された日時からN秒となる日時を出力する関数 DateEx() を作成してください。

関数の仕様は次の通りです。
1. 入力となる日時の書式は任意である。
    → プログラムの都合に合わせてよい。
2. 入力となる時間(秒)は、負の値も許容すること。
    また、負の値が指定された場合、指定の日時よりも前の日時を出力すること
3. 出力する日時は入力の日時と同じ書式をとる文字列であること
4. 出力する日時は正規化されていること
5. 出力先は標準出力、または、バッファのいずれでもよい。

たとえば、DateEx("20080827235925",40)ならば
出力は
「20080828000005」です。

余力があれば時間を省略可能とし、
省略された場合は「現在時刻」を利用するようにしてみてください。
最近は普通にパーサがある時代になったのですね。
ごめんなさい盲点でした^^;;

ということで、「仕様.3」については、
入力の書式は限定しないこととし、出力の書式を限定するようにしてください。

Posted feedbacks - Nested

Flatten Hidden

このお題は日時のparseをさせたいのでしょうか?それとも差分の計算をさせたいのでしょうか?

1
2
3
4
5
6
7
def dateex(d, delta):
  return d + datetime.timedelta(seconds=delta)

if __name__ == '__main__':
  import time
  day = datetime.date(2008, 8, 31)
  print dateex(day, 100000)
ども、raynstardです。
うーん、どっちにになるのでしょう?(笑

このお題の目的は、文字列という日付とは関係ない入力データで
日付の計算をすることです。

そもそもの発端は、シェルで自分自身を
再スケジュールしようとしたらシェルじゃできねぇってことで
計算部分をperlの呼び出しで妥協してしまったことです。

最近の言語には、大抵パーサがあるのですね。
盲点でしたorz
date = "2008/08/27 23:59:25"
addSeconds = 40
> "2008/08/28 00:00:05"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System;

class Program {
    static void Main(string[] args) {
        Console.WriteLine(
            DateEx(Console.ReadLine(), long.Parse(Console.ReadLine()))
            );
        
        Console.WriteLine(
            DateEx(long.Parse(Console.ReadLine()))
            );
        
        Console.ReadLine();
    }

    static string DateEx(string date, long addSeconds) {
        DateTime d;
        DateTime.TryParse(date, out d);
        if(d == null) throw new ArgumentException("日付が正しくありません。", "date");
        return d.AddSeconds((double)addSeconds).ToString();
    }

    static string DateEx(long addSeconds) {
        return DateEx(DateTime.Now.ToString(), addSeconds);
    }
}
1
2
3
4
<?php
function DateEx($time, $diff){
    echo echo date('YmdHis',strtotime($time)+$diff);
}

echoが2つになってしまった・・・。片方いらないです。

1
2
3
DateEx() {
  date -d "$1 $2 seconds"
}

仕様2を満たしていませんでした。

修正と、ついでに1引数に対応。

1
2
3
4
5
6
7
8
DateEx() {
  [ -z "$2" ] && set '' $1
  if [[ $2 == -* ]];then
    date -d "$1 ${2:1} seconds ago"
  else
    date -d "$1 $2 seconds"
  fi
}
てもとのdateコマンドでは動きませんでした。
バージョンていくつでしょう?

$ date --version
date (GNU coreutils) 5.96
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software.  You may redistribute copies of it under the terms of
the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.
There is NO WARRANTY, to the extent permitted by law.

Written by David MacKenzie.
確認したdateのバージョンは、GNU coreutilsの6.10と5.97です。
なるほど、少なくともcoreutils版dateじゃないと使えないんですね。

私のところでの実行例は以下のとおりです。

$ DateEx 'Thu Aug 28 23:59:25 JST 2008' 40
Fri Aug 29 00:00:05 JST 2008
あれ?バージョン同じだぞ?とおもって再度やってみたら動きました。
秒の指定を間違えていたみたいです。
失礼しました。
入出力の日付文字列はISO8601形式です。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:fn="http://www.w3.org/2005/xpath-functions"
  xmlns:my="uri:ja.doukaku.org:my-functions"
  exclude-result-prefixes="my"
  >

  <xsl:output method="text" />

  <xsl:template match="/" >
    <xsl:value-of select="my:DateEx('2008-09-01T10:02:38', 10000)"/>
  </xsl:template>


  <xsl:function name="my:DateEx" as="xs:string">
    <xsl:param name="dstr" as="xs:string" />
    <xsl:param name="sec" as="xs:integer" />

    <xsl:sequence select="xs:string(
      xs:dateTime($dstr) +
      xs:dayTimeDuration(fn:concat('PT',xs:string($sec),'S'))
      )" />
  </xsl:function>

</xsl:stylesheet>
条件2を満たしてなかった。ので、修正。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:fn="http://www.w3.org/2005/xpath-functions"
  xmlns:my="uri:ja.doukaku.org:my-functions"
  exclude-result-prefixes="my"
  >

  <xsl:output method="text" />

  <xsl:template match="/" >
    <xsl:value-of select="my:DateEx('2008-09-01T10:02:38', -1)"/>
  </xsl:template>

  <xsl:function name="my:DateEx" as="xs:string">
    <xsl:param name="dstr" as="xs:string" />
    <xsl:param name="sec" as="xs:integer" />

    <xsl:sequence select="xs:string(
      xs:dateTime($dstr) +
      xs:dayTimeDuration(
        fn:concat(
          (if($sec&lt;0)then'-'else''),
          'PT', xs:string(fn:abs($sec)), 'S'
          )
        )
      )" />
  </xsl:function>

</xsl:stylesheet>

フォーマットの指定がなかったので、とりあえずサンプルと同じにしてみました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class Sample204 {
    private static final DateFormat FORMAT = new SimpleDateFormat("yyyyMMddHHmmss");

    public static String dateEx(String time, int seconds) throws ParseException {
        Date date = FORMAT.parse(time);
        return dateEx(date, seconds);
    }
    public static String dateEx(int seconds) {
        return dateEx(new Date(), seconds);
    }

    private static String dateEx(Date date, int seconds) {
        Calendar cal = Calendar.getInstance();
        cal.setTime( date );
        cal.add(Calendar.SECOND, seconds);
        return FORMAT.format(cal.getTime());
    }


    public static void main(String[] args) {
        try {
            System.out.println(dateEx("20080827235925",40));
            System.out.println(dateEx(0));
        } catch (ParseException ex) {
            ex.printStackTrace();
        }
    }
}
DateTimeと関連モジュールを使って。

入力はコマンドライン引数で、ISO8601形式の日付と秒数を指定します。
日付を省略すると実行時の時刻を使います。

# 入力はISO8601形式じゃなくてもparseしてくれます。ので、お題の条件3.が微妙な感じ
1
2
3
4
5
6
7
8
9
use strict;
use warnings;

use DateTime;
use DateTime::Format::DateParse;

my $d = @ARGV==2 ? DateTime::Format::DateParse->parse_datetime(shift)
                 : DateTime->now(time_zone => q{Asia/Tokyo});
print $d->add(seconds => shift||0)->iso8601,$/;

しまった、お題は「関数を作れ」だった。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
use strict;
use warnings;

use DateTime;
use DateTime::Format::DateParse;

print DateEx(@ARGV),$/;

sub DateEx
{
  (@_>=2 ? DateTime::Format::DateParse->parse_datetime(shift)
         : DateTime->now(time_zone => q{Asia/Tokyo}))
  ->add(seconds => shift||0)->iso8601;
}
Perlにまでパーサっがあったのですね。。。
僕が妥協した時はPOSIXを使ったべた書きでした。
# ほとんどCとかわりません(笑
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env perl
use strict;
use POSIX qw/strftime mktime/;

sub DateEx($$)
{
        my $outDate = '';
        my @t = ($_[0] =~ m/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/);

        $t[0] -= 1900; $t[1] -= 1; @t = reverse @t;
        $t[0] += $_[1];
        mktime( @t );
        return strftime("%Y%m%d%H%M%S", @t);
}

print DateEx("20080827235925",40) . "\n";

__END__
#EOF
Boost.Date_Time で。
入出力の日付形式はコード中に書いてある通り(例:"2008-Sep-01 12:34:56")です。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <string>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/lexical_cast.hpp>

std::string
DateEx(
    const std::string& dstr,
    int                sec
    )
{
  using namespace boost::posix_time;
  return boost::lexical_cast<std::string>(
      ptime(dstr.empty() ? second_clock::local_time()
                         : time_from_string(dstr)
      ) + seconds(sec)
    );
}

int main(int c, char** v)
{
  if ( c == 1 ) {
    std::cout << "usage: " << v[0] << " [<datetime{YYYY-Mon-DD hh:mm:ss}>] <seconds>\n";
    return 0;
  }

  std::cout << DateEx(
      c>=3?v[1]:"",
      boost::lexical_cast<int>(c>=3?v[2]:v[1])
      ) << "\n";

  return 0;
}

Squeak Smalltalk では日時オブジェクト同士の演算が可能です。

1
2
3
4
5
"文字列指定した日時の場合"
'2008-09-01T12:00:00+09:00' asDateAndTime - 10 seconds   "=> 2008-09-01T11:59:50+09:00 "

"現在日時の場合"
DateAndTime now + 15 seconds
D 2.0 + Phobos。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import std.conv;
import std.date;
import std.stdio;

string DateEx(string datetime, int tdelta_in_secs)
{
    d_time t = std.date.parse(datetime);
    d_time new_datetime = t + tdelta_in_secs * std.date.TicksPerSecond;
    return std.date.toString(new_datetime);
}

void main(string[] args)
{
    string datetime;
    int tdelta_in_secs;
    if (args.length == 3) {
        datetime = args[1];
        tdelta_in_secs = toInt(args[2]);
    }
    else {
        d_time now = std.date.getUTCtime;
        datetime = std.date.toString(now);
        tdelta_in_secs = toInt(args[1]);
    }
    writefln("%s", DateEx(datetime, tdelta_in_secs));
}

// eof

使用例も書かないとダメですね。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import std.conv;
import std.date;
import std.stdio;

string DateEx(string datetime, int tdelta_in_secs)
{
    d_time t = std.date.parse(datetime);
    d_time new_datetime = t + tdelta_in_secs * std.date.TicksPerSecond;
    return std.date.toString(new_datetime);
}
unittest {
    assert(DateEx("Mon Sep 01 13:00:00 GMT+0900 2008", -3600) ==
        "Mon Sep 01 12:00:00 GMT+0900 2008");
    assert(DateEx("Mon Sep 01 13:00:00 GMT+0900 2008", 3600) ==
        "Mon Sep 01 14:00:00 GMT+0900 2008");
}

void main(string[] args)
{
    string datetime;
    int tdelta_in_secs;
    if (args.length == 3) {
        datetime = args[1];
        tdelta_in_secs = toInt(args[2]);
    }
    else {
        d_time now = std.date.getUTCtime;
        datetime = std.date.toString(now);
        tdelta_in_secs = toInt(args[1]);
    }
    writefln("%s", DateEx(datetime, tdelta_in_secs));
}

// eof
3.の条件を無視すればこれでもOKです。
(Time.parseはさまざまな書式を受け付けるため)

def date_ex(diff, date = Time.now.to_s)
  puts Time.parse(date) + diff
end

1
2
3
4
5
6
7
8
9
require 'time'

def date_ex(diff, date = Time.now.strftime("%Y/%m/%d %H:%M:%S"))
  raise unless date =~ /\d+\/\d+\/\d+\s+\d+:\d+:\d+/
  puts (Time.parse(date) + diff).strftime("%Y/%m/%d %H:%M:%S")
end

date_ex(100, '2008/09/01 14:06:25') #=> 2008/09/01 14:08:05
date_ex(100) #=> 「現在時刻」から100秒後

VBA for Excel (2003)

1
2
3
4
Function DateEx(str, sec)
  p = InStr(str, " ")
  DateEx = DateValue(Left(str, p - 1)) + TimeValue(Right(str, Len(str) - p)) + sec / 86400
End Function
関数に出力機能まで含めるとなんか使いにくそう。

   '2008 8 27 23 59 25' DateEx 40
2008 8 28 0 0 5

   '2008 8 27 23 59 25' DateEx _40
2008 8 27 23 58 45

   DateEx 100000000
2011 11 3 0 12 46.731
1
2
3
4
5
6
7
8
9
load 'dates'

now =: 6!:0

DateEx =: 3 : 0
(": now '') DateEx y
:
wd 1 tsrep (y * 1000) + tsrep ". x
)

日時の書式は ISO-8601 の「西暦-月-日T時:分:秒」形式です。時間を省略する場合には空文字列を渡すことにしてみました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
(use srfi-13)
(use srfi-19)

(define (date-ex str delta)
  (let ((t (if (string-null? str)
               (current-time time-utc)
               (date->time-utc
                (string->date str "~Y-~m-~dT~H:~M:~S")))))
    (date->string
     (time-utc->date
      (add-duration t (make-time time-duration 0 delta)))
     "~5")))

(define (main args)
  (print (date-ex (cadr args) (string->number (caddr args)))))
net-telent-dateを使ってRFC 2822形式で出力するようにしてみました。
他にも様々な形式をパーズしてくれるライブラリです。
CLの引数の順番はお題の例とは逆にしています。
(date-ex 40 "Thu, 28 Aug 2007 23:59:25 +0900")
;=> "Thu, 30 Aug 2007 00:00:05 +0900" 

(date-ex -3600)
;=> "Mon, 01 Sep 2008 17:56:51 +0900" 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
(require :net-telent-date)
(require :lw-compat)

(defpackage :doukaku-204 (:use :cl :date :lispworks))
(in-package :doukaku-204)

(defun date-ex (sec &optional time-string)
  (when-let (ut (if time-string
                    (parse-time time-string)
                    (get-universal-time)))
    (universal-time-to-rfc2822-date (+ ut sec))))
フォーマットが任意だと楽ちんでいいですね。

> DateEx("2008-09-02 00:00:00 JST", 30)
[1] "2008-09-02 00:00:30 JST"
> DateEx("2008-09-02 00:00:00 JST", -30)
[1] "2008-09-01 23:59:30 JST"
1
2
3
DateEx <- function(d1=Sys.time(), d2=0){
  as.POSIXct(d1) + d2
}

 Javaと余り変わりませんがscala版を。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import    java.text.DateFormat
import    java.text.ParseException
import    java.text.SimpleDateFormat
import    java.util.Calendar

object DateEx {
    val    formatter:DateFormat = new SimpleDateFormat("yyyyMMddHHmmss")
    def DateEx(date:String,diff:Int):String = {
        val    calendar:Calendar = Calendar.getInstance
        calendar.setTime(formatter.parse(date))
        DateEx(calendar,diff)
    }
    def DateEx(diff:Int):String = DateEx(Calendar.getInstance,diff)
    def DateEx(calendar:Calendar,diff:Int):String = {
        calendar.add(Calendar.SECOND,diff)
        formatter.format(calendar.getTime)
    }
    def main(args:Array[String]):Unit = {
        try {
            args.length match {
                case 2 => println(DateEx(args(0),args(1).toInt))
                case 1 => println(DateEx(args(0).toInt))
                case _ => println(DateEx("20080827235925",40))
            }
        } catch {
            case ex:ParseException => println("invalid date format.")
            case ex => ex.printStackTrace
        }
    }
}
JavaScriptのパーサを使用。Firebugで確認。
出力形式にあわせるとこんな入力になった。
toLocaleStringメソッドを使えば"2008年9月2日 8:50:34"のように出力するが、パーサが解釈してくれない。
>>> DateEx('Tue Sep 02 2008 8:30:00',1234)
"Tue Sep 02 2008 08:50:34 GMT+0900"
1
function DateEx(t,s) new Date(Date.parse(t)+s*1000).toString();

こんなのもあたーよ。

なんの工夫もないコードです。
1
2
3
4
5
6
7
import Data.Time

addDate time sec = show $ addUTCTime sec $ read time

main = do
    putStrLn $ addDate "2008-09-02 10:20:30 UTC" 15
    putStrLn $ addDate "2008-09-02 10:20:30 UTC" (-5)

なでしこで。下の二つの関数はほかから流用です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
DateEx("2008/08/27 23:59:25",40)を表示
DateEx("2008/08/27",40)を表示

●DateEx(str,n)
    dateとは配列=区切(str," ")
    もし(date[1]="")ならば、date[1]=今
    配列結合(UNIX2date(date2UNIX(date,0)+n)," ")
●date2UNIX(date,tzd)
    戻(日数差("1970/1/1",date[0])*(60*60*24)+秒差("0:0:0",date[1])+tzd)
●UNIX2date(unix)
    tmpとは配列
    dayとは整数=unix/86400%86400
    unix=unix-day*86400
    tmp[0]=日付加算("1970/1/1","//{day}")
    tmp[1]="{ゼロ埋め(unix/3600%24,2)}:{ゼロ埋め(unix/60%60,2)}:{ゼロ埋め(unix%60,2)}"
    tmpで戻る

モジュールなしで書いた

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#! /usr/bin/perl
use strict;
use warnings;

my $date_string = 20080827235925;
my $add_seconds = 40;

print DateEx($date_string,$add_seconds);

sub DateEx{
    my ($date_string, $add_seconds) = @_;
    
    return 'Error!' unless $date_string =~ /^\d{14}$/;
    return 'Error!' unless $add_seconds =~ /^-?\d+$/;
    
    my ($year,$month,$day,$hour,$minutes,$seconds)
        = $date_string =~ /^(\d{1,4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/;
    my @result = add_seconds($year,$month,$day,$hour,$minutes,$seconds,$add_seconds);
    
    return sprintf("%04d%02d%02d%02d%02d%02d",@result);
}

sub add_seconds{
    my ($year,$month,$day,$hour,$minutes,$seconds,$add_seconds) = @_;
    
    #時間、秒を先に出す
    my ($tmp_day,$result_hour,$result_minutes,$result_seconds)
        = seconds_to_day($add_seconds + day_to_seconds($day-1,$hour,$minutes,$seconds));
    
    #日付を計算
    my ($result_year, $result_month, $result_day)
        = date_add($year,$month,$tmp_day);
    
    return ($result_year,$result_month,$result_day,$result_hour,$result_minutes,$result_seconds);
}

sub day_to_seconds{#何日、何時間、何分の形式を総秒数に変換
    my ($day,$hour,$minutes,$seconds) = @_;
    
    my $SECONDS_PER_MINUTES = 60;
    my $SECONDS_PER_HOUR = $SECONDS_PER_MINUTES * 60;
    my $SECONDS_PER_DAY = $SECONDS_PER_HOUR * 24;
    
    my $total_second = $day     * $SECONDS_PER_DAY
                     + $hour    * $SECONDS_PER_HOUR
                     + $minutes * $SECONDS_PER_MINUTES
                     + $seconds
                     ;
    return $total_second;
}

sub seconds_to_day{#秒数を 何日、何時間、何分の形式に変換
    my ($total_seconds) = @_;
    
    my $SECONDS_PER_MINUTES = 60;
    my $SECONDS_PER_HOUR = $SECONDS_PER_MINUTES * 60;
    my $SECONDS_PER_DAY = $SECONDS_PER_HOUR * 24;
    
    my ($day,$hour,$minutes,$seconds) = (0,0,0,0);
    
    if($total_seconds > 0){
        $day = int($total_seconds / $SECONDS_PER_DAY) + 1;
        $hour = int($total_seconds / $SECONDS_PER_HOUR) % 24;
        $minutes = int($total_seconds / $SECONDS_PER_MINUTES) % 60;
        $seconds = $total_seconds % 60;
    }
    elsif($total_seconds < 0){
        $day = (int(($total_seconds * (-1))/$SECONDS_PER_DAY) + 1) * (-1);
        $total_seconds += $day * $SECONDS_PER_DAY * (-1);
        $hour = int($total_seconds / $SECONDS_PER_HOUR) % 24;
        $minutes = int($total_seconds / $SECONDS_PER_MINUTES) % 60;
        $seconds = $total_seconds % 60;
    }
    return ($day,$hour,$minutes,$seconds);
}

sub date_add{#2008年8月33日は2008年9月2日のような考え方
    my ($year,$month,$day) = @_;
    
    #400年以上のスパンがある場合
    while(abs($day) > (my $DAYS_IN_400YEARS = 365*400+97)){
        if($day > 0){
            $day -= $DAYS_IN_400YEARS;
            $year += 400;
        }
        else{
            $day += $DAYS_IN_400YEARS;
            $year -= 400;
        }
    }
    #1年以上のスパンがある場合
    while(abs($day) > 366){
        if($day > 0){
            if($month <= 2){
                while($day > 366){
                    _uru_or_not($year) ? $day -= 366 : $day -= 365;
                    $year++;
                }
            }
            else{
                while($day > 366){
                    _uru_or_not($year+1) ? $day -= 366 : $day -= 365;
                    $year++;
                }
            }
        }
        else{
            if($month <= 2){
                while($day < -366){
                    _uru_or_not($year-1) ? $day += 366 : $day += 365;
                    $year--
                }
            }
            else{
                while($day < -366){
                    _uru_or_not($year) ? $day += 366 : $day += 365;
                    $year--
                }
            }
        }
    }
    #一月づつ、足すもしくはさかのぼる
    while(!(($day > 0) && (_get_days_of_month($year,$month) >= $day))){
        if($day > 0){
            $day -= _get_days_of_month($year,$month);
            $month++;
            if($month == 13){
                $year++;
                $month = 1;
            }
        }
        else{
            $month--;
            if($month == 0){
                $year--;
                $month = 12;
            }
            $day += (_get_days_of_month($year,$month) + 1);
        }
    }
    return ($year,$month,$day);
}

sub _uru_or_not{#閏年か否かの判定
    my ($year) = @_;
    return 1</