mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
parent
cf73bbd678
commit
dd9ab01d25
13 changed files with 484 additions and 544 deletions
|
@ -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 {
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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
|
@ -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 '+':
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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))); */
|
||||
/* } */
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
Loading…
Reference in a new issue