c/time; patch: time
This commit is contained in:
13
c/c.go
13
c/c.go
@@ -17,6 +17,9 @@
|
|||||||
package c
|
package c
|
||||||
|
|
||||||
// typedef unsigned int uint;
|
// typedef unsigned int uint;
|
||||||
|
// typedef unsigned long ulong;
|
||||||
|
// typedef unsigned long long ulonglong;
|
||||||
|
// typedef long long longlong;
|
||||||
import "C"
|
import "C"
|
||||||
import "unsafe"
|
import "unsafe"
|
||||||
|
|
||||||
@@ -26,10 +29,6 @@ const (
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
Char = int8
|
Char = int8
|
||||||
Long = int32
|
|
||||||
Ulong = uint32
|
|
||||||
LongLong = int64
|
|
||||||
UlongLong = uint64
|
|
||||||
Float = float32
|
Float = float32
|
||||||
Double = float64
|
Double = float64
|
||||||
Pointer = unsafe.Pointer
|
Pointer = unsafe.Pointer
|
||||||
@@ -39,6 +38,12 @@ type (
|
|||||||
type (
|
type (
|
||||||
Int C.int
|
Int C.int
|
||||||
Uint C.uint
|
Uint C.uint
|
||||||
|
|
||||||
|
Long C.long
|
||||||
|
Ulong C.ulong
|
||||||
|
|
||||||
|
LongLong C.longlong
|
||||||
|
UlongLong C.ulonglong
|
||||||
)
|
)
|
||||||
|
|
||||||
type integer interface {
|
type integer interface {
|
||||||
|
|||||||
@@ -143,10 +143,10 @@ func (a *CondAttr) Init(attr *CondAttr) c.Int { return 0 }
|
|||||||
func (a *CondAttr) Destroy() {}
|
func (a *CondAttr) Destroy() {}
|
||||||
|
|
||||||
// llgo:link (*CondAttr).SetClock C.pthread_condattr_setclock
|
// llgo:link (*CondAttr).SetClock C.pthread_condattr_setclock
|
||||||
func (a *CondAttr) SetClock(clock time.ClockID) c.Int { return 0 }
|
func (a *CondAttr) SetClock(clock time.ClockidT) c.Int { return 0 }
|
||||||
|
|
||||||
// llgo:link (*CondAttr).GetClock C.pthread_condattr_getclock
|
// llgo:link (*CondAttr).GetClock C.pthread_condattr_getclock
|
||||||
func (a *CondAttr) GetClock(clock *time.ClockID) c.Int { return 0 }
|
func (a *CondAttr) GetClock(clock *time.ClockidT) c.Int { return 0 }
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import "C"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
_ "unsafe"
|
_ "unsafe"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/c"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -29,10 +31,102 @@ const (
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
type Timespec C.struct_timespec
|
type TimeT C.time_t
|
||||||
|
|
||||||
|
//go:linkname Time C.time
|
||||||
|
func Time(timer *TimeT) TimeT
|
||||||
|
|
||||||
|
//go:linkname Mktime C.mktime
|
||||||
|
func Mktime(timer *Tm) TimeT
|
||||||
|
|
||||||
|
//go:linkname Ctime C.ctime
|
||||||
|
func Ctime(timer *TimeT) string
|
||||||
|
|
||||||
|
//go:linkname Difftime C.difftime
|
||||||
|
func Difftime(end, start TimeT) float64
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
type ClockID C.clockid_t
|
type Tm struct {
|
||||||
|
Sec c.Int
|
||||||
|
Min c.Int
|
||||||
|
Hour c.Int
|
||||||
|
Mday c.Int
|
||||||
|
Mon c.Int
|
||||||
|
Year c.Int
|
||||||
|
Wday c.Int
|
||||||
|
Yday c.Int
|
||||||
|
Isdst c.Int
|
||||||
|
Gmtoff c.Long
|
||||||
|
Zone *c.Char
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname Gmtime C.gmtime
|
||||||
|
func Gmtime(timer *TimeT) *Tm
|
||||||
|
|
||||||
|
//go:linkname Localtime C.localtime
|
||||||
|
func Localtime(timer *TimeT) *Tm
|
||||||
|
|
||||||
|
//go:linkname Strftime C.strftime
|
||||||
|
func Strftime(buf *c.Char, bufSize uintptr, format *c.Char, timeptr *Tm) uintptr
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type ClockT C.clock_t
|
||||||
|
|
||||||
|
//go:linkname Clock C.clock
|
||||||
|
func Clock() ClockT
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type ClockidT C.clockid_t
|
||||||
|
|
||||||
|
const (
|
||||||
|
// the system's real time (i.e. wall time) clock, expressed as the amount of time since the Epoch.
|
||||||
|
// This is the same as the value returned by gettimeofday
|
||||||
|
CLOCK_REALTIME = ClockidT(C.CLOCK_REALTIME)
|
||||||
|
|
||||||
|
// clock that increments monotonically, tracking the time since an arbitrary point, and will continue
|
||||||
|
// to increment while the system is asleep.
|
||||||
|
CLOCK_MONOTONIC = ClockidT(C.CLOCK_MONOTONIC)
|
||||||
|
|
||||||
|
// clock that increments monotonically, tracking the time since an arbitrary point like CLOCK_MONOTONIC.
|
||||||
|
// However, this clock is unaffected by frequency or time adjustments. It should not be compared to
|
||||||
|
// other system time sources.
|
||||||
|
CLOCK_MONOTONIC_RAW = ClockidT(C.CLOCK_MONOTONIC_RAW)
|
||||||
|
|
||||||
|
// like CLOCK_MONOTONIC_RAW, but reads a value cached by the system at context switch. This can be
|
||||||
|
// read faster, but at a loss of accuracy as it may return values that are milliseconds old.
|
||||||
|
CLOCK_MONOTONIC_RAW_APPROX = ClockidT(C.CLOCK_MONOTONIC_RAW_APPROX)
|
||||||
|
|
||||||
|
// clock that increments monotonically, in the same manner as CLOCK_MONOTONIC_RAW, but that does
|
||||||
|
// not increment while the system is asleep. The returned value is identical to the result of
|
||||||
|
// mach_absolute_time() after the appropriate mach_timebase conversion is applied.
|
||||||
|
CLOCK_UPTIME_RAW = ClockidT(C.CLOCK_UPTIME_RAW)
|
||||||
|
|
||||||
|
// like CLOCK_UPTIME_RAW, but reads a value cached by the system at context switch. This can be read
|
||||||
|
// faster, but at a loss of accuracy as it may return values that are milliseconds old.
|
||||||
|
CLOCK_UPTIME_RAW_APPROX = ClockidT(C.CLOCK_UPTIME_RAW_APPROX)
|
||||||
|
|
||||||
|
// clock that tracks the amount of CPU (in user- or kernel-mode) used by the calling process.
|
||||||
|
CLOCK_PROCESS_CPUTIME_ID = ClockidT(C.CLOCK_PROCESS_CPUTIME_ID)
|
||||||
|
|
||||||
|
// clock that tracks the amount of CPU (in user- or kernel-mode) used by the calling thread.
|
||||||
|
CLOCK_THREAD_CPUTIME_ID = ClockidT(C.CLOCK_THREAD_CPUTIME_ID)
|
||||||
|
)
|
||||||
|
|
||||||
|
type Timespec struct {
|
||||||
|
Sec TimeT // seconds
|
||||||
|
Nsec c.Long // and nanoseconds
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname ClockGettime C.clock_gettime
|
||||||
|
func ClockGettime(clkId ClockidT, tp *Timespec) c.Int
|
||||||
|
|
||||||
|
//go:linkname ClockSettime C.clock_settime
|
||||||
|
func ClockSettime(clkId ClockidT, tp *Timespec) c.Int
|
||||||
|
|
||||||
|
//go:linkname ClockGetres C.clock_getres
|
||||||
|
func ClockGetres(clkId ClockidT, res *Timespec) c.Int
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -255,6 +255,80 @@ const (
|
|||||||
daysPer4Years = 365*4 + 1
|
daysPer4Years = 365*4 + 1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// absDate is like date but operates on an absolute time.
|
||||||
|
func absDate(abs uint64, full bool) (year int, month Month, day int, yday int) {
|
||||||
|
// Split into time and day.
|
||||||
|
d := abs / secondsPerDay
|
||||||
|
|
||||||
|
// Account for 400 year cycles.
|
||||||
|
n := d / daysPer400Years
|
||||||
|
y := 400 * n
|
||||||
|
d -= daysPer400Years * n
|
||||||
|
|
||||||
|
// Cut off 100-year cycles.
|
||||||
|
// The last cycle has one extra leap year, so on the last day
|
||||||
|
// of that year, day / daysPer100Years will be 4 instead of 3.
|
||||||
|
// Cut it back down to 3 by subtracting n>>2.
|
||||||
|
n = d / daysPer100Years
|
||||||
|
n -= n >> 2
|
||||||
|
y += 100 * n
|
||||||
|
d -= daysPer100Years * n
|
||||||
|
|
||||||
|
// Cut off 4-year cycles.
|
||||||
|
// The last cycle has a missing leap year, which does not
|
||||||
|
// affect the computation.
|
||||||
|
n = d / daysPer4Years
|
||||||
|
y += 4 * n
|
||||||
|
d -= daysPer4Years * n
|
||||||
|
|
||||||
|
// Cut off years within a 4-year cycle.
|
||||||
|
// The last year is a leap year, so on the last day of that year,
|
||||||
|
// day / 365 will be 4 instead of 3. Cut it back down to 3
|
||||||
|
// by subtracting n>>2.
|
||||||
|
n = d / 365
|
||||||
|
n -= n >> 2
|
||||||
|
y += n
|
||||||
|
d -= 365 * n
|
||||||
|
|
||||||
|
year = int(int64(y) + absoluteZeroYear)
|
||||||
|
yday = int(d)
|
||||||
|
|
||||||
|
if !full {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
day = yday
|
||||||
|
if isLeap(year) {
|
||||||
|
// Leap year
|
||||||
|
switch {
|
||||||
|
case day > 31+29-1:
|
||||||
|
// After leap day; pretend it wasn't there.
|
||||||
|
day--
|
||||||
|
case day == 31+29-1:
|
||||||
|
// Leap day.
|
||||||
|
month = February
|
||||||
|
day = 29
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Estimate month on assumption that every month has 31 days.
|
||||||
|
// The estimate may be too low by at most one month, so adjust.
|
||||||
|
month = Month(day / 31)
|
||||||
|
end := int(daysBefore[month+1])
|
||||||
|
var begin int
|
||||||
|
if day >= end {
|
||||||
|
month++
|
||||||
|
begin = end
|
||||||
|
} else {
|
||||||
|
begin = int(daysBefore[month])
|
||||||
|
}
|
||||||
|
|
||||||
|
month++ // because January is 1
|
||||||
|
day = day - begin + 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// daysBefore[m] counts the number of days in a non-leap year
|
// daysBefore[m] counts the number of days in a non-leap year
|
||||||
// before month m begins. There is an entry for m=12, counting
|
// before month m begins. There is an entry for m=12, counting
|
||||||
// the number of days before January of next year (365).
|
// the number of days before January of next year (365).
|
||||||
|
|||||||
@@ -172,3 +172,342 @@ func (l *Location) lookup(sec int64) (name string, offset int, start, end int64,
|
|||||||
*/
|
*/
|
||||||
panic("todo: Location.lookup")
|
panic("todo: Location.lookup")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tzset takes a timezone string like the one found in the TZ environment
|
||||||
|
// variable, the time of the last time zone transition expressed as seconds
|
||||||
|
// since January 1, 1970 00:00:00 UTC, and a time expressed the same way.
|
||||||
|
// We call this a tzset string since in C the function tzset reads TZ.
|
||||||
|
// The return values are as for lookup, plus ok which reports whether the
|
||||||
|
// parse succeeded.
|
||||||
|
func tzset(s string, lastTxSec, sec int64) (name string, offset int, start, end int64, isDST, ok bool) {
|
||||||
|
var (
|
||||||
|
stdName, dstName string
|
||||||
|
stdOffset, dstOffset int
|
||||||
|
)
|
||||||
|
|
||||||
|
stdName, s, ok = tzsetName(s)
|
||||||
|
if ok {
|
||||||
|
stdOffset, s, ok = tzsetOffset(s)
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return "", 0, 0, 0, false, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// The numbers in the tzset string are added to local time to get UTC,
|
||||||
|
// but our offsets are added to UTC to get local time,
|
||||||
|
// so we negate the number we see here.
|
||||||
|
stdOffset = -stdOffset
|
||||||
|
|
||||||
|
if len(s) == 0 || s[0] == ',' {
|
||||||
|
// No daylight savings time.
|
||||||
|
return stdName, stdOffset, lastTxSec, omega, false, true
|
||||||
|
}
|
||||||
|
|
||||||
|
dstName, s, ok = tzsetName(s)
|
||||||
|
if ok {
|
||||||
|
if len(s) == 0 || s[0] == ',' {
|
||||||
|
dstOffset = stdOffset + secondsPerHour
|
||||||
|
} else {
|
||||||
|
dstOffset, s, ok = tzsetOffset(s)
|
||||||
|
dstOffset = -dstOffset // as with stdOffset, above
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return "", 0, 0, 0, false, false
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s) == 0 {
|
||||||
|
// Default DST rules per tzcode.
|
||||||
|
s = ",M3.2.0,M11.1.0"
|
||||||
|
}
|
||||||
|
// The TZ definition does not mention ';' here but tzcode accepts it.
|
||||||
|
if s[0] != ',' && s[0] != ';' {
|
||||||
|
return "", 0, 0, 0, false, false
|
||||||
|
}
|
||||||
|
s = s[1:]
|
||||||
|
|
||||||
|
var startRule, endRule rule
|
||||||
|
startRule, s, ok = tzsetRule(s)
|
||||||
|
if !ok || len(s) == 0 || s[0] != ',' {
|
||||||
|
return "", 0, 0, 0, false, false
|
||||||
|
}
|
||||||
|
s = s[1:]
|
||||||
|
endRule, s, ok = tzsetRule(s)
|
||||||
|
if !ok || len(s) > 0 {
|
||||||
|
return "", 0, 0, 0, false, false
|
||||||
|
}
|
||||||
|
|
||||||
|
year, _, _, yday := absDate(uint64(sec+unixToInternal+internalToAbsolute), false)
|
||||||
|
|
||||||
|
ysec := int64(yday*secondsPerDay) + sec%secondsPerDay
|
||||||
|
|
||||||
|
// Compute start of year in seconds since Unix epoch.
|
||||||
|
d := daysSinceEpoch(year)
|
||||||
|
abs := int64(d * secondsPerDay)
|
||||||
|
abs += absoluteToInternal + internalToUnix
|
||||||
|
|
||||||
|
startSec := int64(tzruleTime(year, startRule, stdOffset))
|
||||||
|
endSec := int64(tzruleTime(year, endRule, dstOffset))
|
||||||
|
dstIsDST, stdIsDST := true, false
|
||||||
|
// Note: this is a flipping of "DST" and "STD" while retaining the labels
|
||||||
|
// This happens in southern hemispheres. The labelling here thus is a little
|
||||||
|
// inconsistent with the goal.
|
||||||
|
if endSec < startSec {
|
||||||
|
startSec, endSec = endSec, startSec
|
||||||
|
stdName, dstName = dstName, stdName
|
||||||
|
stdOffset, dstOffset = dstOffset, stdOffset
|
||||||
|
stdIsDST, dstIsDST = dstIsDST, stdIsDST
|
||||||
|
}
|
||||||
|
|
||||||
|
// The start and end values that we return are accurate
|
||||||
|
// close to a daylight savings transition, but are otherwise
|
||||||
|
// just the start and end of the year. That suffices for
|
||||||
|
// the only caller that cares, which is Date.
|
||||||
|
if ysec < startSec {
|
||||||
|
return stdName, stdOffset, abs, startSec + abs, stdIsDST, true
|
||||||
|
} else if ysec >= endSec {
|
||||||
|
return stdName, stdOffset, endSec + abs, abs + 365*secondsPerDay, stdIsDST, true
|
||||||
|
} else {
|
||||||
|
return dstName, dstOffset, startSec + abs, endSec + abs, dstIsDST, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tzsetName returns the timezone name at the start of the tzset string s,
|
||||||
|
// and the remainder of s, and reports whether the parsing is OK.
|
||||||
|
func tzsetName(s string) (string, string, bool) {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
if s[0] != '<' {
|
||||||
|
for i, r := range s {
|
||||||
|
switch r {
|
||||||
|
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ',', '-', '+':
|
||||||
|
if i < 3 {
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
return s[:i], s[i:], true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(s) < 3 {
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
return s, "", true
|
||||||
|
} else {
|
||||||
|
for i, r := range s {
|
||||||
|
if r == '>' {
|
||||||
|
return s[1:i], s[i+1:], true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tzsetOffset returns the timezone offset at the start of the tzset string s,
|
||||||
|
// and the remainder of s, and reports whether the parsing is OK.
|
||||||
|
// The timezone offset is returned as a number of seconds.
|
||||||
|
func tzsetOffset(s string) (offset int, rest string, ok bool) {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return 0, "", false
|
||||||
|
}
|
||||||
|
neg := false
|
||||||
|
if s[0] == '+' {
|
||||||
|
s = s[1:]
|
||||||
|
} else if s[0] == '-' {
|
||||||
|
s = s[1:]
|
||||||
|
neg = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// The tzdata code permits values up to 24 * 7 here,
|
||||||
|
// although POSIX does not.
|
||||||
|
var hours int
|
||||||
|
hours, s, ok = tzsetNum(s, 0, 24*7)
|
||||||
|
if !ok {
|
||||||
|
return 0, "", false
|
||||||
|
}
|
||||||
|
off := hours * secondsPerHour
|
||||||
|
if len(s) == 0 || s[0] != ':' {
|
||||||
|
if neg {
|
||||||
|
off = -off
|
||||||
|
}
|
||||||
|
return off, s, true
|
||||||
|
}
|
||||||
|
|
||||||
|
var mins int
|
||||||
|
mins, s, ok = tzsetNum(s[1:], 0, 59)
|
||||||
|
if !ok {
|
||||||
|
return 0, "", false
|
||||||
|
}
|
||||||
|
off += mins * secondsPerMinute
|
||||||
|
if len(s) == 0 || s[0] != ':' {
|
||||||
|
if neg {
|
||||||
|
off = -off
|
||||||
|
}
|
||||||
|
return off, s, true
|
||||||
|
}
|
||||||
|
|
||||||
|
var secs int
|
||||||
|
secs, s, ok = tzsetNum(s[1:], 0, 59)
|
||||||
|
if !ok {
|
||||||
|
return 0, "", false
|
||||||
|
}
|
||||||
|
off += secs
|
||||||
|
|
||||||
|
if neg {
|
||||||
|
off = -off
|
||||||
|
}
|
||||||
|
return off, s, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ruleKind is the kinds of rules that can be seen in a tzset string.
|
||||||
|
type ruleKind int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ruleJulian ruleKind = iota
|
||||||
|
ruleDOY
|
||||||
|
ruleMonthWeekDay
|
||||||
|
)
|
||||||
|
|
||||||
|
// rule is a rule read from a tzset string.
|
||||||
|
type rule struct {
|
||||||
|
kind ruleKind
|
||||||
|
day int
|
||||||
|
week int
|
||||||
|
mon int
|
||||||
|
time int // transition time
|
||||||
|
}
|
||||||
|
|
||||||
|
// tzsetRule parses a rule from a tzset string.
|
||||||
|
// It returns the rule, and the remainder of the string, and reports success.
|
||||||
|
func tzsetRule(s string) (rule, string, bool) {
|
||||||
|
var r rule
|
||||||
|
if len(s) == 0 {
|
||||||
|
return rule{}, "", false
|
||||||
|
}
|
||||||
|
ok := false
|
||||||
|
if s[0] == 'J' {
|
||||||
|
var jday int
|
||||||
|
jday, s, ok = tzsetNum(s[1:], 1, 365)
|
||||||
|
if !ok {
|
||||||
|
return rule{}, "", false
|
||||||
|
}
|
||||||
|
r.kind = ruleJulian
|
||||||
|
r.day = jday
|
||||||
|
} else if s[0] == 'M' {
|
||||||
|
var mon int
|
||||||
|
mon, s, ok = tzsetNum(s[1:], 1, 12)
|
||||||
|
if !ok || len(s) == 0 || s[0] != '.' {
|
||||||
|
return rule{}, "", false
|
||||||
|
|
||||||
|
}
|
||||||
|
var week int
|
||||||
|
week, s, ok = tzsetNum(s[1:], 1, 5)
|
||||||
|
if !ok || len(s) == 0 || s[0] != '.' {
|
||||||
|
return rule{}, "", false
|
||||||
|
}
|
||||||
|
var day int
|
||||||
|
day, s, ok = tzsetNum(s[1:], 0, 6)
|
||||||
|
if !ok {
|
||||||
|
return rule{}, "", false
|
||||||
|
}
|
||||||
|
r.kind = ruleMonthWeekDay
|
||||||
|
r.day = day
|
||||||
|
r.week = week
|
||||||
|
r.mon = mon
|
||||||
|
} else {
|
||||||
|
var day int
|
||||||
|
day, s, ok = tzsetNum(s, 0, 365)
|
||||||
|
if !ok {
|
||||||
|
return rule{}, "", false
|
||||||
|
}
|
||||||
|
r.kind = ruleDOY
|
||||||
|
r.day = day
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s) == 0 || s[0] != '/' {
|
||||||
|
r.time = 2 * secondsPerHour // 2am is the default
|
||||||
|
return r, s, true
|
||||||
|
}
|
||||||
|
|
||||||
|
offset, s, ok := tzsetOffset(s[1:])
|
||||||
|
if !ok {
|
||||||
|
return rule{}, "", false
|
||||||
|
}
|
||||||
|
r.time = offset
|
||||||
|
|
||||||
|
return r, s, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// tzsetNum parses a number from a tzset string.
|
||||||
|
// It returns the number, and the remainder of the string, and reports success.
|
||||||
|
// The number must be between min and max.
|
||||||
|
func tzsetNum(s string, min, max int) (num int, rest string, ok bool) {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return 0, "", false
|
||||||
|
}
|
||||||
|
num = 0
|
||||||
|
for i, r := range s {
|
||||||
|
if r < '0' || r > '9' {
|
||||||
|
if i == 0 || num < min {
|
||||||
|
return 0, "", false
|
||||||
|
}
|
||||||
|
return num, s[i:], true
|
||||||
|
}
|
||||||
|
num *= 10
|
||||||
|
num += int(r) - '0'
|
||||||
|
if num > max {
|
||||||
|
return 0, "", false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if num < min {
|
||||||
|
return 0, "", false
|
||||||
|
}
|
||||||
|
return num, "", true
|
||||||
|
}
|
||||||
|
|
||||||
|
// tzruleTime takes a year, a rule, and a timezone offset,
|
||||||
|
// and returns the number of seconds since the start of the year
|
||||||
|
// that the rule takes effect.
|
||||||
|
func tzruleTime(year int, r rule, off int) int {
|
||||||
|
var s int
|
||||||
|
switch r.kind {
|
||||||
|
case ruleJulian:
|
||||||
|
s = (r.day - 1) * secondsPerDay
|
||||||
|
if isLeap(year) && r.day >= 60 {
|
||||||
|
s += secondsPerDay
|
||||||
|
}
|
||||||
|
case ruleDOY:
|
||||||
|
s = r.day * secondsPerDay
|
||||||
|
case ruleMonthWeekDay:
|
||||||
|
// Zeller's Congruence.
|
||||||
|
m1 := (r.mon+9)%12 + 1
|
||||||
|
yy0 := year
|
||||||
|
if r.mon <= 2 {
|
||||||
|
yy0--
|
||||||
|
}
|
||||||
|
yy1 := yy0 / 100
|
||||||
|
yy2 := yy0 % 100
|
||||||
|
dow := ((26*m1-2)/10 + 1 + yy2 + yy2/4 + yy1/4 - 2*yy1) % 7
|
||||||
|
if dow < 0 {
|
||||||
|
dow += 7
|
||||||
|
}
|
||||||
|
// Now dow is the day-of-week of the first day of r.mon.
|
||||||
|
// Get the day-of-month of the first "dow" day.
|
||||||
|
d := r.day - dow
|
||||||
|
if d < 0 {
|
||||||
|
d += 7
|
||||||
|
}
|
||||||
|
for i := 1; i < r.week; i++ {
|
||||||
|
if d+7 >= daysIn(Month(r.mon), year) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
d += 7
|
||||||
|
}
|
||||||
|
d += int(daysBefore[r.mon-1])
|
||||||
|
if isLeap(year) && r.mon > 2 {
|
||||||
|
d++
|
||||||
|
}
|
||||||
|
s = d * secondsPerDay
|
||||||
|
}
|
||||||
|
|
||||||
|
return s + r.time - off
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"runtime"
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/c/time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// registerLoadFromEmbeddedTZData is called by the time/tzdata package,
|
// registerLoadFromEmbeddedTZData is called by the time/tzdata package,
|
||||||
@@ -313,13 +315,12 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
|
|||||||
tx = append(tx, zoneTrans{when: alpha, index: 0})
|
tx = append(tx, zoneTrans{when: alpha, index: 0})
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// Committed to succeed.
|
// Committed to succeed.
|
||||||
l := &Location{zone: zones, tx: tx, name: name, extend: extend}
|
l := &Location{zone: zones, tx: tx, name: name, extend: extend}
|
||||||
|
|
||||||
// Fill in the cache with information about right now,
|
// Fill in the cache with information about right now,
|
||||||
// since that will be the most common lookup.
|
// since that will be the most common lookup.
|
||||||
sec, _, _ := now()
|
sec := now()
|
||||||
for i := range tx {
|
for i := range tx {
|
||||||
if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
|
if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
|
||||||
l.cacheStart = tx[i].when
|
l.cacheStart = tx[i].when
|
||||||
@@ -350,9 +351,6 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return l, nil
|
return l, nil
|
||||||
*/
|
|
||||||
_ = extend
|
|
||||||
panic("todo")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func findZone(zones []zone, name string, offset int, isDST bool) int {
|
func findZone(zones []zone, name string, offset int, isDST bool) int {
|
||||||
@@ -606,3 +604,9 @@ func gorootZoneSource(goroot string) (string, bool) {
|
|||||||
}
|
}
|
||||||
return goroot + "/lib/time/zoneinfo.zip", true
|
return goroot + "/lib/time/zoneinfo.zip", true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func now() (sec int64) {
|
||||||
|
var tv time.Timespec
|
||||||
|
time.ClockGettime(0, &tv)
|
||||||
|
return int64(tv.Sec)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user