класс DateTime
DateTime
Подкласс Date, который позволяет легко работать с датой, часом, минутой, секундой и смещением.
Класс DateTime считается устаревшим. Используйте класс Time.
DateTime не учитывает високосные секунды и не отслеживает правила летнего времени.
Объект DateTime создаётся с помощью DateTime::new, DateTime::jd, DateTime::ordinal, DateTime::commercial, DateTime::parse, DateTime::strptime, DateTime::now, Time#to_datetime и т. д.
require 'date'
DateTime.new(2001,2,3,4,5,6)
#=> #<DateTime: 2001-02-03T04:05:06+00:00 ...>
Последний элемент даты, часа, минуты или секунды может быть дробным числом. Предполагается, что точность дробного числа не превышает наносекунду.
DateTime.new(2001,2,3.5)
#=> #<DateTime: 2001-02-03T12:00:00+00:00 ...>
Необязательный аргумент — смещение — указывает разницу между местным временем и UTC. Например, Rational(3,24) означает, что время опережает UTC на 3 часа, а Rational(-5,24) — что оно отстаёт от UTC на 5 часов. Смещение должно быть в диапазоне от -1 до +1; предполагается, что его точность не превышает секунды. Значение по умолчанию — ноль (соответствует UTC).
DateTime.new(2001,2,3,4,5,6,Rational(3,24))
#=> #<DateTime: 2001-02-03T04:05:06+03:00 ...>
Смещение также можно указать в виде строки:
DateTime.new(2001,2,3,4,5,6,'+03:00')
#=> #<DateTime: 2001-02-03T04:05:06+03:00 ...>
Необязательный аргумент — день календарной реформы (start) — обозначает номер юлианского дня, который должен быть в диапазоне от 2298874 до 2426355 или равен отрицательной/положительной бесконечности. Значение по умолчанию — Date::ITALY (2299161=1582-10-15).
У объекта DateTime есть различные методы. См. описание каждого из них.
d = DateTime.parse('3rd Feb 2001 04:05:06+03:30')
#=> #<DateTime: 2001-02-03T04:05:06+03:30 ...>
d.hour #=> 4
d.min #=> 5
d.sec #=> 6
d.offset #=> (7/48)
d.zone #=> "+03:30"
d += Rational('1.5')
#=> #<DateTime: 2001-02-04%16:05:06+03:30 ...>
d = d.new_offset('+09:00')
#=> #<DateTime: 2001-02-04%21:35:06+09:00 ...>
d.strftime('%I:%M:%S %p')
#=> "09:35:06 PM"
d > DateTime.new(1999)
#=> true
Когда следует использовать DateTime, а когда — Time?
Распространено ошибочное мнение, что Уильям Шекспир и Мигель де Сервантес умерли в один и тот же день. Это заблуждение стало настолько распространённым, что ЮНЕСКО объявила 23 апреля Всемирным днём книги именно по этой причине. Однако Англия ещё не приняла григорианскую календарную реформу (это произошло лишь в 1752 году), поэтому на самом деле их смерти разделяют 10 дней. Поскольку класс Ruby Time реализует пролептический григорианский календарь и не учитывает календарную реформу, выразить это с помощью объектов Time невозможно. Здесь на помощь приходит DateTime:
shakespeare = DateTime.iso8601('1616-04-23', Date::ENGLAND)
#=> Tue, 23 Apr 1616 00:00:00 +0000
cervantes = DateTime.iso8601('1616-04-23', Date::ITALY)
#=> Sat, 23 Apr 1616 00:00:00 +0000
Уже видно, что-то не так: дни недели различаются. Рассмотрим это подробнее:
cervantes == shakespeare #=> false (shakespeare - cervantes).to_i #=> 10
Это показывает, что на самом деле их смерти разделяют 10 дней (в действительности — 11 дней, поскольку Сервантес умер на день раньше, но был похоронен 23-го числа). Узнать фактическую дату смерти Шекспира можно с помощью метода gregorian, который преобразует её:
shakespeare.gregorian #=> Tue, 03 May 1616 00:00:00 +0000
Таким образом, можно утверждать, что все празднования, проходящие 23 апреля в Стратфорде-на-Эйвоне, на самом деле проводятся не в тот день, поскольку сейчас в Англии используется григорианский календарь. Это становится понятно при переходе через границу даты реформы:
# start off with the anniversary of Shakespeare's birth in 1751
shakespeare = DateTime.iso8601('1751-04-23', Date::ENGLAND)
#=> Tue, 23 Apr 1751 00:00:00 +0000
# add 366 days since 1752 is a leap year and April 23 is after February 29
shakespeare + 366
#=> Thu, 23 Apr 1752 00:00:00 +0000
# add another 365 days to take us to the anniversary in 1753
shakespeare + 366 + 365
#=> Fri, 04 May 1753 00:00:00 +0000
Как видите, если точно отсчитывать число солнечных лет со дня рождения Шекспира, то правильной датой годовщины будет 4 мая, а не 23 апреля.
Так когда же в Ruby следует использовать DateTime, а когда — Time? Почти наверняка вам подойдёт Time, поскольку ваше приложение, вероятно, работает с текущими датами и временем. Однако если вам нужно работать с датами и временем в историческом контексте, используйте DateTime, чтобы не повторить ошибок ЮНЕСКО. Если вам также приходится учитывать часовые пояса, желаем удачи: помните, что, вероятно, речь будет идти о местном солнечном времени, поскольку необходимость в стандартном времени и, в конечном счёте, часовых поясах возникла лишь в XIX веке с появлением железных дорог.
Публичные методы класса
static VALUE
datetime_s__strptime(int argc, VALUE *argv, VALUE klass)
{
return date_s__strptime_internal(argc, argv, klass, "%FT%T%z");
} Разбирает заданное представление даты и времени с помощью заданного шаблона и возвращает хэш разобранных элементов. В отличие от strftime, _strptime не поддерживает указание флагов и ширины.
См. также strptime(3) и strftime.
static VALUE
datetime_s_civil(int argc, VALUE *argv, VALUE klass)
{
return datetime_initialize(argc, argv, d_lite_s_alloc_complex(klass));
} То же, что и DateTime.new.
static VALUE
datetime_s_commercial(int argc, VALUE *argv, VALUE klass)
{
VALUE vy, vw, vd, vh, vmin, vs, vof, vsg, y, fr, fr2, ret;
int w, d, h, min, s, rof;
double sg;
rb_scan_args(argc, argv, "08", &vy, &vw, &vd, &vh, &vmin, &vs, &vof, &vsg);
y = INT2FIX(-4712);
w = 1;
d = 1;
h = min = s = 0;
fr2 = INT2FIX(0);
rof = 0;
sg = DEFAULT_SG;
switch (argc) {
case 8:
val2sg(vsg, sg);
case 7:
val2off(vof, rof);
case 6:
check_numeric(vs, "second");
num2int_with_frac(s, positive_inf);
case 5:
check_numeric(vmin, "minute");
num2int_with_frac(min, 5);
case 4:
check_numeric(vh, "hour");
num2int_with_frac(h, 4);
case 3:
check_numeric(vd, "cwday");
num2int_with_frac(d, 3);
case 2:
check_numeric(vw, "cweek");
w = NUM2INT(vw);
case 1:
check_numeric(vy, "year");
y = vy;
}
{
VALUE nth;
int ry, rw, rd, rh, rmin, rs, rjd, rjd2, ns;
if (!valid_commercial_p(y, w, d, sg,
&nth, &ry,
&rw, &rd, &rjd,
&ns))
rb_raise(eDateError, "invalid date");
if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs))
rb_raise(eDateError, "invalid date");
canon24oc();
rjd2 = jd_local_to_utc(rjd,
time_to_df(rh, rmin, rs),
rof);
ret = d_complex_new_internal(klass,
nth, rjd2,
0, INT2FIX(0),
rof, sg,
0, 0, 0,
rh, rmin, rs,
HAVE_JD | HAVE_TIME);
}
add_frac();
return ret;
} Создаёт объект DateTime, обозначающий заданную дату в формате недели.
DateTime.commercial(2001) #=> #<DateTime: 2001-01-01T00:00:00+00:00 ...>
DateTime.commercial(2002) #=> #<DateTime: 2001-12-31T00:00:00+00:00 ...>
DateTime.commercial(2001,5,6,4,5,6,'+7')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
static VALUE
datetime_s_httpdate(int argc, VALUE *argv, VALUE klass)
{
VALUE str, sg, opt;
argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
switch (argc) {
case 0:
str = rb_str_new2(JULIAN_EPOCH_DATETIME_HTTPDATE);
case 1:
sg = INT2FIX(DEFAULT_SG);
}
{
int argc2 = 1;
VALUE argv2[2], hash;
argv2[0] = str;
argv2[1] = opt;
if (!NIL_P(opt)) argc2++;
hash = date_s__httpdate(argc2, argv2, klass);
return dt_new_by_frags(klass, hash, sg);
}
} Создаёт новый объект DateTime, разбирая строку в соответствии с одним из форматов RFC 2616.
DateTime.httpdate('Sat, 03 Feb 2001 04:05:06 GMT')
#=> #<DateTime: 2001-02-03T04:05:06+00:00 ...>
Вызывает исключение ArgumentError, если длина строки превышает limit. Эту проверку можно отключить, передав limit: nil, но учтите, что разбор может занять много времени.
static VALUE
datetime_s_iso8601(int argc, VALUE *argv, VALUE klass)
{
VALUE str, sg, opt;
argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
switch (argc) {
case 0:
str = rb_str_new2(JULIAN_EPOCH_DATETIME);
case 1:
sg = INT2FIX(DEFAULT_SG);
}
{
int argc2 = 1;
VALUE argv2[2], hash;
argv2[0] = str;
argv2[1] = opt;
if (!NIL_P(opt)) argc2++;
hash = date_s__iso8601(argc2, argv2, klass);
return dt_new_by_frags(klass, hash, sg);
}
} Создаёт новый объект DateTime, разбирая строку в соответствии с одним из распространённых форматов ISO 8601.
DateTime.iso8601('2001-02-03T04:05:06+07:00')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.iso8601('20010203T040506+0700')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.iso8601('2001-W05-6T04:05:06+07:00')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
Вызывает исключение ArgumentError, если длина строки превышает limit. Эту проверку можно отключить, передав limit: nil, но учтите, что разбор может занять много времени.
static VALUE
datetime_s_jd(int argc, VALUE *argv, VALUE klass)
{
VALUE vjd, vh, vmin, vs, vof, vsg, jd, fr, fr2, ret;
int h, min, s, rof;
double sg;
rb_scan_args(argc, argv, "06", &vjd, &vh, &vmin, &vs, &vof, &vsg);
jd = INT2FIX(0);
h = min = s = 0;
fr2 = INT2FIX(0);
rof = 0;
sg = DEFAULT_SG;
switch (argc) {
case 6:
val2sg(vsg, sg);
case 5:
val2off(vof, rof);
case 4:
check_numeric(vs, "second");
num2int_with_frac(s, positive_inf);
case 3:
check_numeric(vmin, "minute");
num2int_with_frac(min, 3);
case 2:
check_numeric(vh, "hour");
num2int_with_frac(h, 2);
case 1:
check_numeric(vjd, "jd");
num2num_with_frac(jd, 1);
}
{
VALUE nth;
int rh, rmin, rs, rjd, rjd2;
if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs))
rb_raise(eDateError, "invalid date");
canon24oc();
decode_jd(jd, &nth, &rjd);
rjd2 = jd_local_to_utc(rjd,
time_to_df(rh, rmin, rs),
rof);
ret = d_complex_new_internal(klass,
nth, rjd2,
0, INT2FIX(0),
rof, sg,
0, 0, 0,
rh, rmin, rs,
HAVE_JD | HAVE_TIME);
}
add_frac();
return ret;
} Создаёт объект DateTime, обозначающий заданный хронологический номер юлианского дня.
DateTime.jd(2451944) #=> #<DateTime: 2001-02-03T00:00:00+00:00 ...>
DateTime.jd(2451945) #=> #<DateTime: 2001-02-04T00:00:00+00:00 ...>
DateTime.jd(Rational('0.5'))
#=> #<DateTime: -4712-01-01T12:00:00+00:00 ...>
static VALUE
datetime_s_jisx0301(int argc, VALUE *argv, VALUE klass)
{
VALUE str, sg, opt;
argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
switch (argc) {
case 0:
str = rb_str_new2(JULIAN_EPOCH_DATETIME);
case 1:
sg = INT2FIX(DEFAULT_SG);
}
{
int argc2 = 1;
VALUE argv2[2], hash;
argv2[0] = str;
argv2[1] = opt;
if (!NIL_P(opt)) argc2++;
hash = date_s__jisx0301(argc2, argv2, klass);
return dt_new_by_frags(klass, hash, sg);
}
} Создаёт новый объект DateTime, разбирая строку в соответствии с одним из распространённых форматов JIS X 0301.
DateTime.jisx0301('H13.02.03T04:05:06+07:00')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
Если эра не указана, используется формат предыдущей эпохи, а также предполагается эра Хэйсэй.
DateTime.jisx0301('13.02.03T04:05:06+07:00')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
Вызывает исключение ArgumentError, если длина строки превышает limit. Эту проверку можно отключить, передав limit: nil, но учтите, что разбор может занять много времени.
# File ext/json/lib/json/add/date_time.rb, line 10
def self.json_create(object)
args = object.values_at('y', 'm', 'd', 'H', 'M', 'S')
of_a, of_b = object['of'].split('/')
if of_b and of_b != '0'
args << Rational(of_a.to_i, of_b.to_i)
else
args << of_a
end
args << object['sg']
civil(*args)
end См. as_json.
static VALUE
datetime_s_civil(int argc, VALUE *argv, VALUE klass)
{
return datetime_initialize(argc, argv, d_lite_s_alloc_complex(klass));
} То же, что и DateTime.new.
static VALUE
datetime_s_now(int argc, VALUE *argv, VALUE klass)
{
VALUE vsg, nth, ret;
double sg;
#ifdef HAVE_CLOCK_GETTIME
struct timespec ts;
#else
struct timeval tv;
#endif
time_t sec;
struct tm tm;
long sf, of;
int y, ry, m, d, h, min, s;
rb_scan_args(argc, argv, "01", &vsg);
if (argc < 1)
sg = DEFAULT_SG;
else
sg = NUM2DBL(vsg);
#ifdef HAVE_CLOCK_GETTIME
if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
rb_sys_fail("clock_gettime");
sec = ts.tv_sec;
#else
if (gettimeofday(&tv, NULL) == -1)
rb_sys_fail("gettimeofday");
sec = tv.tv_sec;
#endif
tzset();
if (!localtime_r(&sec, &tm))
rb_sys_fail("localtime");
y = tm.tm_year + 1900;
m = tm.tm_mon + 1;
d = tm.tm_mday;
h = tm.tm_hour;
min = tm.tm_min;
s = tm.tm_sec;
if (s == 60)
s = 59;
#ifdef HAVE_STRUCT_TM_TM_GMTOFF
of = tm.tm_gmtoff;
#elif defined(HAVE_TIMEZONE)
#if defined(HAVE_ALTZONE) && !defined(_AIX)
of = (long)-((tm.tm_isdst > 0) ? altzone : timezone);
#else
of = (long)-timezone;
if (tm.tm_isdst) {
time_t sec2;
tm.tm_isdst = 0;
sec2 = mktime(&tm);
of += (long)difftime(sec2, sec);
}
#endif
#elif defined(HAVE_TIMEGM)
{
time_t sec2;
sec2 = timegm(&tm);
of = (long)difftime(sec2, sec);
}
#else
{
struct tm tm2;
time_t sec2;
if (!gmtime_r(&sec, &tm2))
rb_sys_fail("gmtime");
tm2.tm_isdst = tm.tm_isdst;
sec2 = mktime(&tm2);
of = (long)difftime(sec, sec2);
}
#endif
#ifdef HAVE_CLOCK_GETTIME
sf = ts.tv_nsec;
#else
sf = tv.tv_usec * 1000;
#endif
if (of < -DAY_IN_SECONDS || of > DAY_IN_SECONDS) {
of = 0;
rb_warning("invalid offset is ignored");
}
decode_year(INT2FIX(y), -1, &nth, &ry);
ret = d_complex_new_internal(klass,
nth, 0,
0, LONG2NUM(sf),
(int)of, GREGORIAN,
ry, m, d,
h, min, s,
HAVE_CIVIL | HAVE_TIME);
{
get_d1(ret);
set_sg(dat, sg);
}
return ret;
} Создаёт объект DateTime, обозначающий текущее время.
DateTime.now #=> #<DateTime: 2011-06-11T21:20:44+09:00 ...>
static VALUE
datetime_s_ordinal(int argc, VALUE *argv, VALUE klass)
{
VALUE vy, vd, vh, vmin, vs, vof, vsg, y, fr, fr2, ret;
int d, h, min, s, rof;
double sg;
rb_scan_args(argc, argv, "07", &vy, &vd, &vh, &vmin, &vs, &vof, &vsg);
y = INT2FIX(-4712);
d = 1;
h = min = s = 0;
fr2 = INT2FIX(0);
rof = 0;
sg = DEFAULT_SG;
switch (argc) {
case 7:
val2sg(vsg, sg);
case 6:
val2off(vof, rof);
case 5:
check_numeric(vs, "second");
num2int_with_frac(s, positive_inf);
case 4:
check_numeric(vmin, "minute");
num2int_with_frac(min, 4);
case 3:
check_numeric(vh, "hour");
num2int_with_frac(h, 3);
case 2:
check_numeric(vd, "yday");
num2int_with_frac(d, 2);
case 1:
check_numeric(vy, "year");
y = vy;
}
{
VALUE nth;
int ry, rd, rh, rmin, rs, rjd, rjd2, ns;
if (!valid_ordinal_p(y, d, sg,
&nth, &ry,
&rd, &rjd,
&ns))
rb_raise(eDateError, "invalid date");
if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs))
rb_raise(eDateError, "invalid date");
canon24oc();
rjd2 = jd_local_to_utc(rjd,
time_to_df(rh, rmin, rs),
rof);
ret = d_complex_new_internal(klass,
nth, rjd2,
0, INT2FIX(0),
rof, sg,
0, 0, 0,
rh, rmin, rs,
HAVE_JD | HAVE_TIME);
}
add_frac();
return ret;
} Создаёт объект DateTime, обозначающий заданную порядковую дату.
DateTime.ordinal(2001,34) #=> #<DateTime: 2001-02-03T00:00:00+00:00 ...>
DateTime.ordinal(2001,34,4,5,6,'+7')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.ordinal(2001,-332,-20,-55,-54,'+7')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
static VALUE
datetime_s_parse(int argc, VALUE *argv, VALUE klass)
{
VALUE str, comp, sg, opt;
argc = rb_scan_args(argc, argv, "03:", &str, &comp, &sg, &opt);
switch (argc) {
case 0:
str = rb_str_new2(JULIAN_EPOCH_DATETIME);
case 1:
comp = Qtrue;
case 2:
sg = INT2FIX(DEFAULT_SG);
}
{
int argc2 = 2;
VALUE argv2[3], hash;
argv2[0] = str;
argv2[1] = comp;
argv2[2] = opt;
if (!NIL_P(opt)) argc2++;
hash = date_s__parse(argc2, argv2, klass);
return dt_new_by_frags(klass, hash, sg);
}
} Разбирает заданное представление даты и времени и создаёт объект DateTime.
Этот метод не является валидатором. Если входная строка не соответствует допустимым форматам в точности, результат может оказаться непонятным. По возможности следует использовать вместо этого метода DateTime.strptime.
Если второй необязательный аргумент равен true, а обнаруженный год находится в диапазоне от «00» до «99», год преобразуется в полный формат.
DateTime.parse('2001-02-03T04:05:06+07:00')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.parse('20010203T040506+0700')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.parse('3rd Feb 2001 04:05:06 PM')
#=> #<DateTime: 2001-02-03T16:05:06+00:00 ...>
Вызывает исключение ArgumentError, если длина строки превышает limit. Эту проверку можно отключить, передав limit: nil, но учтите, что разбор может занять много времени.
static VALUE
datetime_s_rfc2822(int argc, VALUE *argv, VALUE klass)
{
VALUE str, sg, opt;
argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
switch (argc) {
case 0:
str = rb_str_new2(JULIAN_EPOCH_DATETIME_RFC3339);
case 1:
sg = INT2FIX(DEFAULT_SG);
}
{
int argc2 = 1;
VALUE argv2[2], hash;
argv2[0] = str;
argv2[1] = opt;
if (!NIL_P(opt)) argc2++;
hash = date_s__rfc2822(argc2, argv2, klass);
return dt_new_by_frags(klass, hash, sg);
}
} Создаёт новый объект DateTime, разбирая строку в соответствии с одним из распространённых форматов RFC 2822.
DateTime.rfc2822('Sat, 3 Feb 2001 04:05:06 +0700')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
Вызывает исключение ArgumentError, если длина строки превышает limit. Эту проверку можно отключить, передав limit: nil, но учтите, что разбор может занять много времени.
static VALUE
datetime_s_rfc3339(int argc, VALUE *argv, VALUE klass)
{
VALUE str, sg, opt;
argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
switch (argc) {
case 0:
str = rb_str_new2(JULIAN_EPOCH_DATETIME);
case 1:
sg = INT2FIX(DEFAULT_SG);
}
{
int argc2 = 1;
VALUE argv2[2], hash;
argv2[0] = str;
argv2[1] = opt;
if (!NIL_P(opt)) argc2++;
hash = date_s__rfc3339(argc2, argv2, klass);
return dt_new_by_frags(klass, hash, sg);
}
} Создаёт новый объект DateTime, разбирая строку в соответствии с одним из распространённых форматов RFC 3339.
DateTime.rfc3339('2001-02-03T04:05:06+07:00')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
Вызывает исключение ArgumentError, если длина строки превышает limit. Эту проверку можно отключить, передав limit: nil, но учтите, что разбор может занять много времени.
static VALUE
datetime_s_rfc2822(int argc, VALUE *argv, VALUE klass)
{
VALUE str, sg, opt;
argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
switch (argc) {
case 0:
str = rb_str_new2(JULIAN_EPOCH_DATETIME_RFC3339);
case 1:
sg = INT2FIX(DEFAULT_SG);
}
{
int argc2 = 1;
VALUE argv2[2], hash;
argv2[0] = str;
argv2[1] = opt;
if (!NIL_P(opt)) argc2++;
hash = date_s__rfc2822(argc2, argv2, klass);
return dt_new_by_frags(klass, hash, sg);
}
} Создаёт новый объект DateTime, разбирая строку в соответствии с одним из распространённых форматов RFC 2822.
DateTime.rfc2822('Sat, 3 Feb 2001 04:05:06 +0700')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
Вызывает исключение ArgumentError, если длина строки превышает limit. Эту проверку можно отключить, передав limit: nil, но учтите, что разбор может занять много времени.
static VALUE
datetime_s_strptime(int argc, VALUE *argv, VALUE klass)
{
VALUE str, fmt, sg;
rb_scan_args(argc, argv, "03", &str, &fmt, &sg);
switch (argc) {
case 0:
str = rb_str_new2(JULIAN_EPOCH_DATETIME);
case 1:
fmt = rb_str_new2("%FT%T%z");
case 2:
sg = INT2FIX(DEFAULT_SG);
}
{
VALUE argv2[2], hash;
argv2[0] = str;
argv2[1] = fmt;
hash = date_s__strptime(2, argv2, klass);
return dt_new_by_frags(klass, hash, sg);
}
} Разбирает заданное представление даты и времени с помощью заданного шаблона и создаёт объект DateTime. В отличие от strftime, strptime не поддерживает указание флагов и ширины.
DateTime.strptime('2001-02-03T04:05:06+07:00', '%Y-%m-%dT%H:%M:%S%z')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.strptime('03-02-2001 04:05:06 PM', '%d-%m-%Y %I:%M:%S %p')
#=> #<DateTime: 2001-02-03T16:05:06+00:00 ...>
DateTime.strptime('2001-W05-6T04:05:06+07:00', '%G-W%V-%uT%H:%M:%S%z')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.strptime('2001 04 6 04 05 06 +7', '%Y %U %w %H %M %S %z')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.strptime('2001 05 6 04 05 06 +7', '%Y %W %u %H %M %S %z')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.strptime('-1', '%s')
#=> #<DateTime: 1969-12-31T23:59:59+00:00 ...>
DateTime.strptime('-1000', '%Q')
#=> #<DateTime: 1969-12-31T23:59:59+00:00 ...>
DateTime.strptime('sat3feb014pm+7', '%a%d%b%y%H%p%z')
#=> #<DateTime: 2001-02-03T16:00:00+07:00 ...>
См. также strptime(3) и strftime.
static VALUE
datetime_s_xmlschema(int argc, VALUE *argv, VALUE klass)
{
VALUE str, sg, opt;
argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
switch (argc) {
case 0:
str = rb_str_new2(JULIAN_EPOCH_DATETIME);
case 1:
sg = INT2FIX(DEFAULT_SG);
}
{
int argc2 = 1;
VALUE argv2[2], hash;
argv2[0] = str;
argv2[1] = opt;
if (!NIL_P(opt)) argc2++;
hash = date_s__xmlschema(argc2, argv2, klass);
return dt_new_by_frags(klass, hash, sg);
}
} Создаёт новый объект DateTime, разбирая строку в соответствии с одним из распространённых форматов XML Schema.
DateTime.xmlschema('2001-02-03T04:05:06+07:00')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
Вызывает исключение ArgumentError, если длина строки превышает limit. Эту проверку можно отключить, передав limit: nil, но учтите, что разбор может занять много времени.
Публичные методы экземпляра
# File ext/json/lib/json/add/date_time.rb, line 39
def as_json(*)
{
JSON.create_id => self.class.name,
'y' => year,
'm' => month,
'd' => day,
'H' => hour,
'M' => min,
'S' => sec,
'of' => offset.to_s,
'sg' => start,
}
end Методы DateTime#as_json и DateTime.json_create можно использовать для сериализации и десериализации объекта DateTime; см. Marshal.
Метод DateTime#as_json сериализует self, возвращая хэш из двух элементов, представляющий self:
require 'json/add/datetime'
x = DateTime.now.as_json
# => {"json_class"=>"DateTime", "y"=>2023, "m"=>11, "d"=>21, "sg"=>2299161.0}
Метод JSON.create десериализует такой хэш и возвращает объект DateTime:
DateTime.json_create(x) # BUG? Raises Date::Error "invalid date"
static VALUE
dt_lite_deconstruct_keys(VALUE self, VALUE keys)
{
return deconstruct_keys(self, keys, /* is_datetime=true */ 1);
} Возвращает хэш пар имя/значение для сопоставления с образцом. Возможные ключи: :year, :month, :day, :wday, :yday, :hour, :min, :sec, :sec_fraction, :zone.
Возможные варианты использования:
dt = DateTime.new(2022, 10, 5, 13, 30)
if d in wday: 1..5, hour: 10..18 # uses deconstruct_keys underneath
puts "Working time"
end
#=> prints "Working time"
case dt
in year: ...2022
puts "too old"
in month: ..9
puts "quarter 1-3"
in wday: 1..5, month:
puts "working day in month #{month}"
end
#=> prints "working day in month 10"
Обратите внимание, что разбор по образцу также можно сочетать с проверкой класса:
if d in DateTime(wday: 1..5, hour: 10..18, day: ..7) puts "Working time, first week of the month" end
static VALUE
d_lite_hour(VALUE self)
{
get_d1(self);
return INT2FIX(m_hour(dat));
} Возвращает час в диапазоне (0..23):
DateTime.new(2001, 2, 3, 4, 5, 6).hour # => 4
static VALUE
dt_lite_iso8601(int argc, VALUE *argv, VALUE self)
{
long n = 0;
rb_check_arity(argc, 0, 1);
if (argc >= 1)
n = NUM2LONG(argv[0]);
return rb_str_append(strftimev("%Y-%m-%d", self, set_tmx),
iso8601_timediv(self, n));
} Этот метод эквивалентен strftime(‘%FT%T%:z’). Необязательный аргумент n задаёт количество цифр для дробной части секунд.
DateTime.parse('2001-02-03T04:05:06.123456789+07:00').iso8601(9)
#=> "2001-02-03T04:05:06.123456789+07:00"
static VALUE
dt_lite_jisx0301(int argc, VALUE *argv, VALUE self)
{
long n = 0;
rb_check_arity(argc, 0, 1);
if (argc >= 1)
n = NUM2LONG(argv[0]);
return rb_str_append(d_lite_jisx0301(self),
iso8601_timediv(self, n));
} Возвращает строку в формате JIS X 0301. Необязательный аргумент n задаёт количество цифр для дробной части секунд.
DateTime.parse('2001-02-03T04:05:06.123456789+07:00').jisx0301(9)
#=> "H13.02.03T04:05:06.123456789+07:00"
static VALUE
d_lite_min(VALUE self)
{
get_d1(self);
return INT2FIX(m_min(dat));
} Возвращает минуту в диапазоне (0..59):
DateTime.new(2001, 2, 3, 4, 5, 6).min # => 5
static VALUE
d_lite_new_offset(int argc, VALUE *argv, VALUE self)
{
VALUE vof;
int rof;
rb_scan_args(argc, argv, "01", &vof);
rof = 0;
if (argc >= 1)
val2off(vof, rof);
return dup_obj_with_new_offset(self, rof);
} Создаёт копию self и сбрасывает её смещение.
d = DateTime.new(2001,2,3,4,5,6,'-02:00')
#=> #<DateTime: 2001-02-03T04:05:06-02:00 ...>
d.new_offset('+09:00') #=> #<DateTime: 2001-02-03T15:05:06+09:00 ...>
static VALUE
d_lite_offset(VALUE self)
{
get_d1(self);
return m_of_in_day(dat);
} Возвращает смещение.
DateTime.parse('04pm+0730').offset #=> (5/16)
static VALUE
dt_lite_rfc3339(int argc, VALUE *argv, VALUE self)
{
return dt_lite_iso8601(argc, argv, self);
} Этот метод эквивалентен strftime(‘%FT%T%:z’). Необязательный аргумент n задаёт количество цифр для дробной части секунд.
DateTime.parse('2001-02-03T04:05:06.123456789+07:00').rfc3339(9)
#=> "2001-02-03T04:05:06.123456789+07:00"
static VALUE
d_lite_sec(VALUE self)
{
get_d1(self);
return INT2FIX(m_sec(dat));
} Возвращает секунду в диапазоне (0..59):
DateTime.new(2001, 2, 3, 4, 5, 6).sec # => 6
static VALUE
d_lite_sec_fraction(VALUE self)
{
get_d1(self);
return m_sf_in_sec(dat);
} Возвращает дробную часть секунды в диапазоне (Rational(0, 1)…Rational(1, 1)):
DateTime.new(2001, 2, 3, 4, 5, 6.5).sec_fraction # => (1/2)
static VALUE
dt_lite_strftime(int argc, VALUE *argv, VALUE self)
{
return date_strftime_internal(argc, argv, self,
"%Y-%m-%dT%H:%M:%S%:z", set_tmx);
} Возвращает строковое представление self, отформатированное согласно заданному +format:
DateTime.now.strftime # => "2022-07-01T11:03:19-05:00"
Другие форматы см. в разделе Форматы дат и времени:
static VALUE
datetime_to_date(VALUE self)
{
get_d1a(self);
if (simple_dat_p(adat)) {
VALUE new = d_lite_s_alloc_simple(cDate);
{
get_d1b(new);
bdat->s = adat->s;
bdat->s.jd = m_local_jd(adat);
return new;
}
}
else {
VALUE new = d_lite_s_alloc_simple(cDate);
{
get_d1b(new);
copy_complex_to_simple(new, &bdat->s, &adat->c);
bdat->s.jd = m_local_jd(adat);
bdat->s.flags &= ~(HAVE_DF | HAVE_TIME | COMPLEX_DAT);
return new;
}
}
} Возвращает объект Date, обозначающий self.
static VALUE
datetime_to_datetime(VALUE self)
{
return self;
} Возвращает self.
# File ext/json/lib/json/add/date_time.rb, line 62 def to_json(*args) as_json.to_json(*args) end
Возвращает строку JSON, представляющую self:
require 'json/add/datetime' puts DateTime.now.to_json
Результат:
{"json_class":"DateTime","y":2023,"m":11,"d":21,"sg":2299161.0}
static VALUE
dt_lite_to_s(VALUE self)
{
return strftimev("%Y-%m-%dT%H:%M:%S%:z", self, set_tmx);
} Возвращает строку в формате ISO 8601. (Этот метод не использует расширенные представления.)
DateTime.new(2001,2,3,4,5,6,'-7').to_s
#=> "2001-02-03T04:05:06-07:00"
static VALUE
datetime_to_time(VALUE self)
{
get_d1(self);
if (m_julian_p(dat)) {
VALUE g = d_lite_gregorian(self);
get_d1a(g);
dat = adat;
self = g;
}
{
VALUE t;
t = rb_funcall(rb_cTime,
rb_intern("new"),
7,
m_real_year(dat),
INT2FIX(m_mon(dat)),
INT2FIX(m_mday(dat)),
INT2FIX(m_hour(dat)),
INT2FIX(m_min(dat)),
f_add(INT2FIX(m_sec(dat)),
m_sf_in_sec(dat)),
INT2FIX(m_of(dat)));
RB_GC_GUARD(self); /* may be the converted gregorian */
return t;
}
} Возвращает объект Time, обозначающий self.
Этот метод эквивалентен strftime(‘%FT%T%:z’). Необязательный аргумент n задаёт количество цифр для дробной части секунд.
DateTime.parse('2001-02-03T04:05:06.123456789+07:00').iso8601(9)
#=> "2001-02-03T04:05:06.123456789+07:00"
static VALUE
d_lite_zone(VALUE self)
{
get_d1(self);
return m_zone(dat);
} Возвращает часовой пояс.
DateTime.parse('04pm+0730').zone #=> "+07:30"
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.