Revert "Use 64-bit years"

This reverts commit cfc3a953ae.
This commit is contained in:
Justine Tunney 2022-05-12 06:11:22 -07:00
parent cf73bbd678
commit dd9ab01d25
13 changed files with 484 additions and 544 deletions

View file

@ -83,13 +83,13 @@ typedef struct {
} div_t;
typedef struct {
long quot;
long rem;
long int quot;
long int rem;
} ldiv_t;
typedef struct {
long long quot;
long long rem;
long long int quot;
long long int rem;
} lldiv_t;
typedef struct {

View file

@ -1,26 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/time/time.h"
/**
* Returns true if `year` is a leap year.
*/
bool _isleap(int64_t year) {
return !(year % 4) && ((year % 100) || !(year % 400));
}

View file

@ -1,41 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/time/time.h"
/*
* Since everything in _isleap() is modulo 400 (or a factor of 400), we
* know that:
*
* isleap(y) == isleap(y % 400)
*
* And so:
*
* isleap(a + b) == isleap((a + b) % 400)
*
* Or:
*
* isleap(a + b) == isleap(a % 400 + b % 400)
*
* This is true even if % means modulo rather than Fortran remainder
* (which is allowed by C89 but not by C99 or later). We use this to
* avoid addition overflow problems.
*/
bool _isleapsum(int64_t a, int64_t b) {
return _isleap(a % 400 + b % 400);
}

File diff suppressed because it is too large Load diff

View file

@ -16,11 +16,9 @@
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "libc/bits/pushpop.h"
#include "libc/fmt/itoa.h"
#include "libc/fmt/fmt.h"
#include "libc/inttypes.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/time/time.h"
#include "libc/time/tz.internal.h"
#include "libc/unicode/locale.h"
@ -115,56 +113,14 @@ strftime_add(const char *str, char *pt, const char *ptlim)
return pt;
}
static dontinline char *
strftime_conv(int64_t x, char *pt, const char *ptlim, int width, char pad)
static char *
strftime_conv(int n, const char *format, char *pt, const char *ptlim)
{
int n;
char buf[21], *ptr, *end;
end = FormatInt64(buf, x);
for (n = width - (end - buf); n > 0; --n) {
if (pt < ptlim) {
*pt++ = pad;
}
}
char buf[INT_STRLEN_MAXIMUM(int) + 1];
(sprintf)(buf, format, n);
return strftime_add(buf, pt, ptlim);
}
static dontinline char *
strftime_conv_d(int64_t n, char *pt, const char *ptlim)
{
return strftime_conv(n, pt, ptlim, 0, 0);
}
static dontinline char *
strftime_conv_2d(int64_t n, char *pt, const char *ptlim)
{
return strftime_conv(n, pt, ptlim, pushpop(2L), pushpop(' '));
}
static dontinline char *
strftime_conv_0(int64_t n, char *pt, const char *ptlim, int width)
{
return strftime_conv(n, pt, ptlim, width, pushpop('0'));
}
static dontinline char *
strftime_conv_02d(int64_t n, char *pt, const char *ptlim)
{
return strftime_conv_0(n, pt, ptlim, pushpop(2L));
}
static dontinline char *
strftime_conv_03d(int64_t n, char *pt, const char *ptlim)
{
return strftime_conv_0(n, pt, ptlim, pushpop(3L));
}
static dontinline char *
strftime_conv_04d(int64_t n, char *pt, const char *ptlim)
{
return strftime_conv_0(n, pt, ptlim, pushpop(4L));
}
/*
** POSIX and the C Standard are unclear or inconsistent about
** what %C and %y do if the year is negative or exceeds 9999.
@ -175,15 +131,15 @@ strftime_conv_04d(int64_t n, char *pt, const char *ptlim)
static char *
strftime_yconv(
int64_t a,
int64_t b,
int a,
int b,
bool convert_top,
bool convert_yy,
char *pt,
const char *ptlim)
{
int64_t lead;
int64_t trail;
register int lead;
register int trail;
trail = a % DIVISOR + b % DIVISOR;
lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;
@ -198,10 +154,10 @@ strftime_yconv(
if (convert_top) {
if (lead == 0 && trail < 0)
pt = strftime_add("-0", pt, ptlim);
else pt = strftime_conv_02d(lead, pt, ptlim);
else pt = strftime_conv(lead, "%02d", pt, ptlim);
}
if (convert_yy)
pt = strftime_conv_02d(((trail < 0) ? -trail : trail), pt, ptlim);
pt = strftime_conv(((trail < 0) ? -trail : trail), "%02d", pt, ptlim);
return pt;
}
@ -271,7 +227,7 @@ label:
pt = strftime_fmt("%m/%d/%y", t, pt, ptlim, warnp);
continue;
case 'd':
pt = strftime_conv_02d(t->tm_mday, pt, ptlim);
pt = strftime_conv(t->tm_mday, "%02d", pt, ptlim);
continue;
case 'E':
case 'O':
@ -286,21 +242,21 @@ label:
*/
goto label;
case 'e':
pt = strftime_conv_2d(t->tm_mday, pt, ptlim);
pt = strftime_conv(t->tm_mday, "%2d", pt, ptlim);
continue;
case 'F':
pt = strftime_fmt("%Y-%m-%d", t, pt, ptlim, warnp);
continue;
case 'H':
pt = strftime_conv_02d(t->tm_hour, pt, ptlim);
pt = strftime_conv(t->tm_hour, "%02d", pt, ptlim);
continue;
case 'I':
pt = strftime_conv_02d((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
pt, ptlim);
pt = strftime_conv((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
"%02d", pt, ptlim);
continue;
case 'j':
pt = strftime_conv_03d(t->tm_yday + 1, pt, ptlim);
pt = strftime_conv(t->tm_yday + 1, "%03d", pt, ptlim);
continue;
case 'k':
/*
@ -313,7 +269,8 @@ label:
** "%l" have been swapped.
** (ado, 1993-05-24)
*/
pt = strftime_conv_2d(t->tm_hour, pt, ptlim);
pt = strftime_conv(t->tm_hour, "%2d",
pt, ptlim);
continue;
#ifdef KITCHEN_SINK
case 'K':
@ -333,15 +290,17 @@ label:
** "%l" have been swapped.
** (ado, 1993-05-24)
*/
pt = strftime_conv_2d((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
pt, ptlim);
pt = strftime_conv((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
"%2d", pt, ptlim);
continue;
case 'M':
pt = strftime_conv_02d(t->tm_min, pt, ptlim);
pt = strftime_conv(t->tm_min, "%02d",
pt, ptlim);
continue;
case 'm':
pt = strftime_conv_02d(t->tm_mon + 1, pt, ptlim);
pt = strftime_conv(t->tm_mon + 1, "%02d",
pt, ptlim);
continue;
case 'n':
pt = strftime_add("\n", pt, ptlim);
@ -361,12 +320,14 @@ label:
ptlim, warnp);
continue;
case 'S':
pt = strftime_conv_02d(t->tm_sec, pt, ptlim);
pt = strftime_conv(t->tm_sec, "%02d", pt,
ptlim);
continue;
case 's':
{
struct tm tm;
char buf[21];
char buf[INT_STRLEN_MAXIMUM(
time_t) + 1];
time_t mkt;
tm = *t;
@ -385,7 +346,14 @@ label:
&& tm.tm_sec == tm_1.tm_sec))
return NULL;
}
strftime_conv_d(mkt, pt, ptlim);
if (TYPE_SIGNED(time_t)) {
intmax_t n = mkt;
(sprintf)(buf, "%"PRIdMAX, n);
} else {
uintmax_t n = mkt;
(sprintf)(buf, "%"PRIuMAX, n);
}
pt = strftime_add(buf, pt, ptlim);
}
continue;
case 'T':
@ -395,10 +363,9 @@ label:
pt = strftime_add("\t", pt, ptlim);
continue;
case 'U':
pt = strftime_conv_02d(
(t->tm_yday + DAYSPERWEEK -
t->tm_wday) / DAYSPERWEEK,
pt, ptlim);
pt = strftime_conv((t->tm_yday + DAYSPERWEEK -
t->tm_wday) / DAYSPERWEEK,
"%02d", pt, ptlim);
continue;
case 'u':
/*
@ -407,9 +374,9 @@ label:
** [1 (Monday) - 7]"
** (ado, 1993-05-24)
*/
pt = strftime_conv_d((t->tm_wday == 0) ?
DAYSPERWEEK : t->tm_wday,
pt, ptlim);
pt = strftime_conv((t->tm_wday == 0) ?
DAYSPERWEEK : t->tm_wday,
"%d", pt, ptlim);
continue;
case 'V': /* ISO 8601 week number */
case 'G': /* ISO 8601 year (four digits) */
@ -433,22 +400,22 @@ label:
** (ado, 1996-01-02)
*/
{
int64_t year;
int64_t base;
int64_t yday;
int64_t wday;
int64_t w;
int year;
int base;
int yday;
int wday;
int w;
year = t->tm_year;
base = TM_YEAR_BASE;
yday = t->tm_yday;
wday = t->tm_wday;
for ( ; ; ) {
int64_t len;
int64_t bot;
int64_t top;
int len;
int bot;
int top;
len = _isleapsum(year, base) ?
len = isleap_sum(year, base) ?
DAYSPERLYEAR :
DAYSPERNYEAR;
/*
@ -477,13 +444,13 @@ label:
break;
}
--base;
yday += _isleapsum(year, base) ?
yday += isleap_sum(year, base) ?
DAYSPERLYEAR :
DAYSPERNYEAR;
}
if (*format == 'V')
pt = strftime_conv_02d(
w, pt, ptlim);
pt = strftime_conv(w, "%02d",
pt, ptlim);
else if (*format == 'g') {
*warnp = IN_ALL;
pt = strftime_yconv(year, base,
@ -503,15 +470,15 @@ label:
pt = strftime_fmt("%e-%b-%Y", t, pt, ptlim, warnp);
continue;
case 'W':
pt = strftime_conv_02d(
pt = strftime_conv(
(t->tm_yday + DAYSPERWEEK -
(t->tm_wday ?
(t->tm_wday - 1) :
(DAYSPERWEEK - 1))) / DAYSPERWEEK,
pt, ptlim);
"%02d", pt, ptlim);
continue;
case 'w':
pt = strftime_conv_d(t->tm_wday, pt, ptlim);
pt = strftime_conv(t->tm_wday, "%d", pt, ptlim);
continue;
case 'X':
pt = strftime_fmt(Locale->X_fmt, t, pt, ptlim, warnp);
@ -566,7 +533,7 @@ label:
diff /= SECSPERMIN;
diff = (diff / MINSPERHOUR) * 100 +
(diff % MINSPERHOUR);
pt = strftime_conv_04d(diff, pt, ptlim);
pt = strftime_conv(diff, "%04d", pt, ptlim);
}
continue;
case '+':

View file

@ -37,10 +37,10 @@ Copyright 2005-2019 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\"");
char *strptime(const char *s, const char *f, struct tm *tm) {
size_t len;
int i, w, neg, adj, min, range, itemsize, *dest, dummy;
const char *ex, *ss;
long i, w, neg, adj, min, range, itemsize, *dest, dummy;
long want_century = 0, century = 0, relyear = 0;
size_t len;
int want_century = 0, century = 0, relyear = 0;
while (*f) {
if (*f != '%') {
if (isspace(*f)) {

View file

@ -2,24 +2,16 @@
#define COSMOPOLITAN_LIBC_TIME_STRUCT_TM_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/**
* Time component structure.
*
* This structure is used by gmtime() and localtime(). It's not a kernel
* interface. We use a different ABI than most C libraries here, because
* we want to support timestamps dating back to the big bang, as well as
* timestamps through much of the stelliferous era.
*/
struct tm {
int64_t tm_year; /* minus 1900 */
int64_t tm_mon; /* 0-indexed */
int64_t tm_mday; /* 1-indexed */
int64_t tm_hour;
int64_t tm_min;
int64_t tm_sec;
int64_t tm_wday;
int64_t tm_yday;
int64_t tm_isdst;
int32_t tm_sec;
int32_t tm_min;
int32_t tm_hour;
int32_t tm_mday; /* 1-indexed */
int32_t tm_mon; /* 0-indexed */
int32_t tm_year; /* minus 1900 */
int32_t tm_wday;
int32_t tm_yday;
int32_t tm_isdst;
int64_t tm_gmtoff;
const char *tm_zone;
};

View file

@ -66,8 +66,6 @@ extern long double (*nowl)(void);
long double ConvertTicksToNanos(uint64_t);
void RefreshTime(void);
bool _isleap(int64_t);
bool _isleapsum(int64_t, int64_t);
double difftime(int64_t, int64_t) dontthrow pureconst;
char *iso8601(char[hasatleast 20], struct tm *);
size_t wcsftime(wchar_t *, size_t, const wchar_t *, const struct tm *);

View file

@ -70,9 +70,7 @@ o/$(MODE)/libc/time/localtime.o: \
OVERRIDE_CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED
# guarantee constant divisor optimization
o/$(MODE)/libc/time/isleap.o \
o/$(MODE)/libc/time/isleapsum.o: \
o/$(MODE)/libc/time/now.o: \
OVERRIDE_CFLAGS += \
-O3

View file

@ -5,7 +5,6 @@
#include "libc/errno.h"
#include "libc/inttypes.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/ok.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
@ -378,6 +377,7 @@ int64_t time2posix_z(timezone_t, int64_t) nosideeffect;
*/
#define TYPE_BIT(type) (sizeof(type) * CHAR_BIT)
#define TYPE_SIGNED(type) (((type) -1) < 0)
#define TWOS_COMPLEMENT(t) ((t) ~ (t) 0 < 0)
/* Max and min values of the integer type T, of which only the bottom
@ -443,6 +443,19 @@ int64_t time2posix_z(timezone_t, int64_t) nosideeffect;
# define UNINIT_TRAP 0
#endif
#ifdef DEBUG
# define UNREACHABLE() abort()
#elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__)
# define UNREACHABLE() __builtin_unreachable()
#elif defined __has_builtin
# if __has_builtin(__builtin_unreachable)
# define UNREACHABLE() __builtin_unreachable()
# endif
#endif
#ifndef UNREACHABLE
# define UNREACHABLE() ((void) 0)
#endif
/*
** For the benefit of GNU folk...
** '_(MSGID)' uses the current locale's message library string for MSGID.
@ -510,6 +523,22 @@ char *ctime_r(int64_t const *, char *);
#define EPOCH_YEAR 1970
#define EPOCH_WDAY TM_THURSDAY
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
/*
** Since everything in isleap is modulo 400 (or a factor of 400), we know that
** isleap(y) == isleap(y % 400)
** and so
** isleap(a + b) == isleap((a + b) % 400)
** or
** isleap(a + b) == isleap(a % 400 + b % 400)
** This is true even if % means modulo rather than Fortran remainder
** (which is allowed by C89 but not by C99 or later).
** We use this to avoid addition overflow problems.
*/
#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_TZ_PRIVATE_H_ */

View file

@ -20,7 +20,6 @@
#include "libc/calls/struct/timeval.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/mem/fmt.h"
#include "libc/mem/mem.h"
#include "libc/sysv/consts/clock.h"
@ -34,11 +33,10 @@
static char *xiso8601_impl(struct timespec *opt_ts, int sswidth) {
char *p;
int i, j, n;
struct tm tm;
struct timespec ts;
int64_t sec, subsec;
char buf[128], ibuf[21];
char timebuf[64], zonebuf[8];
if (opt_ts) {
sec = opt_ts->tv_sec;
subsec = opt_ts->tv_nsec;
@ -58,20 +56,10 @@ static char *xiso8601_impl(struct timespec *opt_ts, int sswidth) {
sswidth = 7; /* windows nt uses hectonanoseconds */
}
localtime_r(&sec, &tm);
i = strftime(buf, 64, "%Y-%m-%dT%H:%M:%S", &tm);
p = FormatInt64(ibuf, subsec);
for (n = sswidth - (p - ibuf); n > 0; --n) {
if (i < sizeof(buf)) {
buf[i++] = '0';
}
}
for (j = 0; ibuf[j]; ++j) {
if (i < sizeof(buf)) {
buf[i++] = ibuf[j];
}
}
strftime(buf + i, sizeof(buf) - i, "%z", &tm);
return strdup(buf);
strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%S", &tm);
strftime(zonebuf, sizeof(zonebuf), "%z", &tm);
(asprintf)(&p, "%s.%0*ld%s", timebuf, sswidth, subsec, zonebuf);
return p;
}
/**

View file

@ -18,10 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
#include "libc/time/time.h"
@ -79,6 +76,12 @@ TEST(strftime_201, rfc822_GoogleStandardTime) {
FormatTime("%a, %d %b %y %T %z", localtime(&t)));
}
/* TEST(xiso8601, testModernity_TODO) { */
/* int64_t t = (1600 - 1970) * 31536000; */
/* ASSERT_STREQ("1600-01-01T00:00:00Z", */
/* FormatTime("%Y-%m-%dT%H:%M:%SZ", gmtime(&t))); */
/* } */
TEST(xiso8601, testAtLeastBetterThanTraditionalUnixLimit) {
int64_t t = 10737418235;
ASSERT_STREQ("2310-04-04T16:10:35Z",
@ -91,36 +94,8 @@ TEST(xiso8601, testSomethingHuge) {
FormatTime("%Y-%m-%dT%H:%M:%SZ", gmtime(&t)));
}
// this requires 52 bit year
TEST(xiso8601, testBigBang) {
struct tm tm;
int64_t t = -13700000000L * 31536000L;
CHECK_NOTNULL(gmtime_r(&t, &tm));
ASSERT_STREQ("-13690902019-07-22T00:00:00Z",
FormatTime("%Y-%m-%dT%H:%M:%SZ", &tm));
}
// stelliferous era is 10**6 < n < 10**14 years (71-bit)
// we support up to approx. 10**11 yr after the big bang
TEST(xiso8601, testMostOfStelliferousEra) {
struct tm tm;
int64_t t = -13700000000L + 100000000000 /*000*/ * 31536000L;
CHECK_NOTNULL(gmtime_r(&t, &tm));
ASSERT_STREQ("99933607290-12-11T04:26:40Z",
FormatTime("%Y-%m-%dT%H:%M:%SZ", &tm));
}
const char *GmtimeFormatTime(void) {
struct tm tm;
int64_t t = -13700000000L * 31536000L;
CHECK_NOTNULL(gmtime_r(&t, &tm));
return FormatTime("%Y-%m-%dT%H:%M:%SZ", &tm);
}
BENCH(strftime, bench) {
struct tm tm;
int64_t t = -13700000000L * 31536000L;
CHECK_NOTNULL(gmtime_r(&t, &tm));
EZBENCH2("strftime", donothing, FormatTime("%Y-%m-%dT%H:%M:%SZ", &tm));
EZBENCH2("gmtime+strftime", donothing, GmtimeFormatTime());
}
/* TEST(xiso8601, testMostOfStelliferousEra_TODO) { */
/* int64_t t = INT64_MAX; */
/* ASSERT_STREQ("somethinghuge-01-01T00:00:00Z", */
/* FormatTime("%Y-%m-%dT%H:%M:%SZ", gmtime(&t))); */
/* } */

View file

@ -2796,12 +2796,12 @@ UNIX MODULE
stdio
Allows clock_getres, clock_gettime, close, dup, fchdir, fstat,
fsync, ftruncate, getdents, getegid, getrandom, geteuid, getgid,
getgroups, getitimer, getpgid, getpgrp, getpid, getppid,
getresgid, getresuid, getrlimit, getsid, gettimeofday, getuid,
lseek, madvise, brk, mmap, mprotect, munmap, nanosleep, pipe,
pipe2, poll, pread, preadv, pwrite, pwritev, read, readv,
Allows clock_getres, clock_gettime, close, dup, dup2, dup3,
fchdir, fstat, fsync, ftruncate, getdents, getegid, getrandom,
geteuid, getgid, getgroups, getitimer, getpgid, getpgrp, getpid,
getppid, getresgid, getresuid, getrlimit, getsid, gettimeofday,
getuid, lseek, madvise, brk, mmap, mprotect, munmap, nanosleep,
pipe, pipe2, poll, pread, preadv, pwrite, pwritev, read, readv,
recvfrom, recvmsg, select, sendmsg, sendto, setitimer, shutdown,
sigaction, sigprocmask, sigreturn, socketpair, umask, wait4,
write, writev.
@ -2866,49 +2866,17 @@ UNIX MODULE
├─→ year,mon,mday,hour,min,sec,gmtoffsec,wday,yday,dst:int,zone:str
└─→ nil,unix.Errno
Breaks down UNIX timestamp into Shaka Zulu Time numbers.
Breaks down UNIX timestamp into Zulu Time numbers.
This function is like localtime() except it always returns Greenwich
Mean Time irrespective of the TZ environment variable.
For example:
>: unix.gmtime(unix.clock_gettime())
2022 5 11 22 43 20 0 3 130 0 "GMT"
Here's how you might format a localized timestamp with nanoseconds:
>: unixsec, nanos = unix.clock_gettime()
>: year,mon,mday,hour,min,sec = unix.localtime(unixsec)
>: '%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.9dZ' % {year,mon,mday,hour,min,sec,nanos}
"2022-05-11T15:46:32.160239978Z"
`year` is the year, where zero is defined as 0 A.D. This value may
be on the interval `-13.7e9 ≤ year ≤ 10e14` which is the time from
the Big Bang, through most of the Stelliferous Era.
`mon` is the month of the year, on the interval `1 ≤ mon ≤ 12` in
order to make printf style formatting easier.
`mday` is the day of the month, on the interval `1 ≤ mday ≤ 31` in
order to make printf style formatting easier.
`hour` represent hours, on the interval `0 ≤ hour ≤ 23`. - `min`
represents minutes, on the interval `0 ≤ min ≤ 59`.
`sec` represents seconds, on the interval `0 ≤ sec ≤ 60`. Please
note this is a 61 second interval in order to accommodate highly
rare leap second events.
`wday` is the day of the week, on the interval `0 ≤ wday ≤ 6`.
`yday` is the day of the year on the interval `0 ≤ yday ≤ 365`.
`gmtoff` is the Shaka Zulu time offset in seconds, which should be
on the interval ±93600 seconds.
`dst` will be 1 if daylight savings, 0 if not daylight savings, or
-1 if it couldn't be determined.
- `mon` 1 ≤ mon ≤ 12
- `mday` 1 ≤ mday ≤ 31
- `hour` 0 ≤ hour ≤ 23
- `min` 0 ≤ min ≤ 59
- `sec` 0 ≤ sec ≤ 60
- `gmtoff` ±93600 seconds
- `wday` 0 ≤ wday ≤ 6
- `yday` 0 ≤ yday ≤ 365
- `dst` 1 if daylight savings, 0 if not, -1 if not unknown
unix.localtime(unixts:int)
├─→ year,mon,mday,hour,min,sec,gmtoffsec,wday,yday,dst:int,zone:str
@ -2919,21 +2887,7 @@ UNIX MODULE
>: unix.localtime(unix.clock_gettime())
2022 4 28 2 14 22 -25200 4 117 1 "PDT"
This follows the same API as gmtime() except it takes the `TZ`
environment variable into consideration to determine the most
appropriate localization.
Please see the gmtime() function for documentaiton on the meaning of
the various returned values.
Here's an example of how you might format a localized timestamp:
>: unixsec, nanos = unix.clock_gettime()
>: year, mon, mday, hour, min, sec, gmtoffsec = unix.localtime(unixsec)
>: '%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.9d%+.2d%.2d' % {
year, mon, mday, hour, min, sec, nanos,
gmtoffsec / (60 * 60), math.abs(gmtoffsec) % 60}
"2022-05-11T15:46:32.160239978-0700"
This follows the same API as gmtime() which has further details.
Your redbean ships with a subset of the time zone database.