Hello list I am trying to adapt the tz code to a local system without any timezone database (AmigaOS). I got the code up and running and everything seems to work as intended. But one thing about the code puzzles me. I need to implement "time_t time(time_t *p)" which is the very last part of localtime.c. Should this code return time as local time or as GMT time ? Because I cannot get the time calculations to work properly. I use tzsetwall() to guess the timezone from the systems locale zone information (GMT+1, etc) and tzset() to load timezone from the TZ environment variable. Should "time_t time(time_t *p)" try to compensate if lclptr is set, or should it always just return the plain system time? I hope someone knows the answer and also thank you for any clarifications on this issue. Kind regards Carsten Larsen
On Oct 8, 2016, at 10:27 AM, Carsten Larsen <cs@innolan.dk> wrote:
I am trying to adapt the tz code to a local system without any timezone database (AmigaOS). I got the code up and running and everything seems to work as intended. But one thing about the code puzzles me.
I need to implement "time_t time(time_t *p)" which is the very last part of localtime.c.
No, time() is *not* part of localtime.c. It was originally the UNIX API to get the current time of day, and...
Should this code return time as local time or as GMT time ?
...it returns the time as "seconds since the Epoch", which, in a POSIX-conforming system, is a count of all the non-leap seconds that have elapsed between January 1, 1970, 00:00:00 UTC and now. (Yes, non-leap seconds.) Some non-UNIX systems might implement it as well. Current UNIX systems also provide it, although it's generally implemented on top of the newer gettimeofday() or clock_gettime() APIs, which provide higher-resolution time values.
On Sat, Oct 8, 2016, at 13:27, Carsten Larsen wrote:
Hello list
I am trying to adapt the tz code to a local system without any timezone database (AmigaOS). I got the code up and running and everything seems to work as intended. But one thing about the code puzzles me.
I need to implement "time_t time(time_t *p)" which is the very last part of localtime.c. Should this code return time as local time or as GMT time ? Because I cannot get the time calculations to work properly.
This function returns the current time as a time_t. On Windows and Unix-like systems, this is UTC seconds since midnight of January 1, 1970. Does AmigaOS not already have such a function? There's no implementation in tzcode because it's expected to already exist as part of a lower level of the C runtime library (and historically it was a direct system call to the Unix kernel)
I use tzsetwall() to guess the timezone from the systems locale zone information (GMT+1, etc) and tzset() to load timezone from the TZ environment variable. Should "time_t time(time_t *p)" try to compensate if lclptr is set, or should it always just return the plain system time?
What is the native format of the system time? What are you doing to determine what the actual time is?
Den 08-10-2016 kl. 20:03 skrev Random832:
On Sat, Oct 8, 2016, at 13:27, Carsten Larsen wrote:
Hello list
I am trying to adapt the tz code to a local system without any timezone database (AmigaOS). I got the code up and running and everything seems to work as intended. But one thing about the code puzzles me.
I need to implement "time_t time(time_t *p)" which is the very last part of localtime.c. Should this code return time as local time or as GMT time ? Because I cannot get the time calculations to work properly.
This function returns the current time as a time_t. On Windows and Unix-like systems, this is UTC seconds since midnight of January 1, 1970.
Does AmigaOS not already have such a function? There's no implementation in tzcode because it's expected to already exist as part of a lower level of the C runtime library (and historically it was a direct system call to the Unix kernel)
AmigaOS uses an Epoch of January 1, 1978, 00:00:00 instead of January 1, 1970, 00:00:00 UTC. Time zone is not specified. The Epoch difference is easy to calculate. 2 leap years and 6 normal. No leap seconds: 2922 is the number of days between 1.1.1970 and 1.1.1978 2922 * 24 * 60 * 60 = 252460800
What is the native format of the system time? What are you doing to determine what the actual time is?
The actual time is is number of seconds since 1.1.1978 and possibly a GMT offset (if the user have bothered to set it. The system does not take it into consideration). There is no concept of daylight saving rules and no concept of UTC. I guess I need to determine the exact point of January 1, 1970, 00:00:00 *UTC* on my (AmigaOS) timeline in order to use the time.h functions in tz, and I assume the TZ variable and tz code can help me to do so. Right ? Kind regard Carsten Larsen
On Oct 8, 2016, at 12:46 PM, Carsten Larsen <cs@innolan.dk> wrote:
AmigaOS uses an Epoch of January 1, 1978, 00:00:00 instead of January 1, 1970, 00:00:00 UTC. Time zone is not specified.
By "time zone is not specified" do you mean 1) the Epoch is local time, rather than UTC or 2) the Epoch is UTC, but there's no way to specify the local time zone in AmigaOS or 3) something else?
On Sat, Oct 8, 2016, at 15:46, Carsten Larsen wrote:
The actual time is is number of seconds since 1.1.1978 and possibly a GMT offset (if the user have bothered to set it. The system does not take it into consideration). There is no concept of daylight saving rules and no concept of UTC.
So does AmigaOS not ship with a standard C library with its own time.h functions? Even if they only handle one system-defined timezone, seeing which of localtime/gmtime gives 1978-01-01 00:00:00 when you pass in a value of 0 would be useful.
I guess I need to determine the exact point of January 1, 1970, 00:00:00 *UTC* on my (AmigaOS) timeline in order to use the time.h functions in tz, and I assume the TZ variable and tz code can help me to do so. Right ?
You need to figure out how the system's native functions handle it. Also http://distributed.amiga.org/misc/timezone.text may be useful. Maybe look at what this "ixemul" thing does. The version at http://www.nic.funet.fi/index/gnu/funet/historical-funet-gnu-area-from-early... appears to treat it as UTC - from gettimeofday.c: __time_req->tr_node.io_Command = TR_GETSYSTIME; omask = syscall (SYS_sigsetmask, ~0); DoIO((struct IORequest *)__time_req); syscall (SYS_sigsetmask, omask); *tp = __time_req->tr_time; /* add the offset from unix to amigados time system */ tp->tv_sec += (8*365+2) * 24 * 3600;
On 8 Oct 2016, at 20:46, Carsten Larsen <cs@innolan.dk> wrote:
The Epoch difference is easy to calculate. 2 leap years and 6 normal. No leap seconds:
Posix time-since-the-epoch ignores leap seconds. The epoch is “approximately” midnight at the beginning of 1970. (Currently 26 seconds out.) jch
Date: Sat, 8 Oct 2016 21:59:44 +0100 From: John Haxby <john.haxby@oracle.com> Message-ID: <E732F782-B470-4FF9-8754-CA018858AF94@oracle.com> | The epoch is approximately=94 midnight at the beginning of 1970. No, it is exactly the beginning of 1970 (UTC). The issue is that the "seconds" that are counted are not international standard seconds, but posix seconds, which are defined to be 1/86400 of the length of the day in which they occur. That means that posix seconds can be slightly (very slightly) longer (or in principal, shorter) than IS seconds. If you're trying to measure precise time intervals, posix seconds are useless (though they're fine if all you care about is the nearest 1/10 of a second or so) but for working with calendars, they're ideal, as there's no need to keep a table of when leap seconds occur (which, as they're unpredictable, is the only way to deal with them.) kre
On 9 Oct 2016, at 02:52, Robert Elz <kre@munnari.OZ.AU> wrote:
Date: Sat, 8 Oct 2016 21:59:44 +0100 From: John Haxby <john.haxby@oracle.com> Message-ID: <E732F782-B470-4FF9-8754-CA018858AF94@oracle.com>
| The epoch is approximately=94 midnight at the beginning of 1970.
No, it is exactly the beginning of 1970 (UTC). The issue is that the "seconds" that are counted are not international standard seconds, but posix seconds, which are defined to be 1/86400 of the length of the day in which they occur. That means that posix seconds can be slightly (very slightly) longer (or in principal, shorter) than IS seconds.
If you're trying to measure precise time intervals, posix seconds are useless (though they're fine if all you care about is the nearest 1/10 of a second or so) but for working with calendars, they're ideal, as there's no need to keep a table of when leap seconds occur (which, as they're unpredictable, is the only way to deal with them.)
http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_...
4.14 Seconds Since the Epoch
A value that approximates the number of seconds that have elapsed since the Epoch.
It goes on to say that “the relationship between the actual time of day and the current value for seconds since the Epoch is unspecified” and “each and every day since the Epoch shall be accounted for by exactly 86400 seconds”. To my eyes, it’s quite obviously trying to avoid mentioning leap seconds and the fact that some days actually have a different number of seconds. The trouble is, once you introduce leap seconds and a defined conversion from seconds since the Epoch to struct tm then you introduce a whole lot of pain doing arithmetic with struct tm. A second really is a second though, there’s nothing about approximating the length of a second. Interestingly, some people use gettimeofday(2) as an interval timer and can’t cope with it going backwards when there’s a leap second so they trade accuracy for uptime :) and use ntpd -x even though they should be using a monotonic clock (time since an unspecified epoch, often boot time) which doesn’t go backwards. Also anyone who stores a timestamp as seconds since the epoch is in trouble because there are values that represent two distinct times, ie 23:59:59 and 23:59:60 UTC when there’s a leap second inserted. They still do it, of course, and sooner or later the trading systems people are going to start complaining loudly that This Will Not Do™. (I’ve mentioned before that ntp_gettime, which isn’t posix, allows for discovering whether or not you’re in a leap second so you can convert clock_gettime(CLOCK_REALTIME) to 23:59:60 for the affected one billion nanoseconds.) Time is so much fun :) jch
John Haxby wrote:
anyone who stores a timestamp as seconds since the epoch is in trouble because there are values that represent two distinct times, ie 23:59:59 and 23:59:60 UTC when there’s a leap second inserted. They still do it, of course, and sooner or later the trading systems people are going to start complaining loudly that This Will Not Do
The trading systems people know about this problem, and fix it in different ways. For example, the Brazilian trading system inserts a leap second during a weekend outside of trading hours, which means that it can be one second ahead of the rest of the world for a few days. The Japanese system uses linear leap smearing instead, slowing its clocks for the two hours before the leap second, which means its clocks' errors gradually grow from 0 to 1 second ahead during those two hours. It is a bit of a mess. For more, see a previous thread on the topic, e.g.: http://mm.icann.org/pipermail/tz/2015-May/022280.html
On 2016-10-08 13:46, Carsten Larsen wrote:
Den 08-10-2016 kl. 20:03 skrev Random832:
On Sat, Oct 8, 2016, at 13:27, Carsten Larsen wrote:
Hello list
I am trying to adapt the tz code to a local system without any timezone database (AmigaOS). I got the code up and running and everything seems to work as intended. But one thing about the code puzzles me.
I need to implement "time_t time(time_t *p)" which is the very last part of localtime.c. Should this code return time as local time or as GMT time ? Because I cannot get the time calculations to work properly.
This function returns the current time as a time_t. On Windows and Unix-like systems, this is UTC seconds since midnight of January 1, 1970.
Does AmigaOS not already have such a function? There's no implementation in tzcode because it's expected to already exist as part of a lower level of the C runtime library (and historically it was a direct system call to the Unix kernel)
AmigaOS uses an Epoch of January 1, 1978, 00:00:00 instead of January 1, 1970, 00:00:00 UTC. Time zone is not specified.
The Epoch difference is easy to calculate. 2 leap years and 6 normal. No leap seconds:
2922 is the number of days between 1.1.1970 and 1.1.1978 2922 * 24 * 60 * 60 = 252460800
What is the native format of the system time? What are you doing to determine what the actual time is?
The actual time is is number of seconds since 1.1.1978 and possibly a GMT offset (if the user have bothered to set it. The system does not take it into consideration). There is no concept of daylight saving rules and no concept of UTC.
I guess I need to determine the exact point of January 1, 1970, 00:00:00 *UTC* on my (AmigaOS) timeline in order to use the time.h functions in tz, and I assume the TZ variable and tz code can help me to do so. Right ?
POSIX Base Definitions 4.16 Seconds Since the Epoch gives the calculation in POSIX time (UTC ignoring leap seconds): http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_... -- Take care. Thanks, Brian Inglis, Calgary, Alberta, Canada
On Oct 8, 2016, at 12:46 PM, Carsten Larsen <cs@innolan.dk> wrote:
AmigaOS uses an Epoch of January 1, 1978, 00:00:00 instead of January 1, 1970, 00:00:00 UTC. Time zone is not specified.
The Epoch difference is easy to calculate.
As "January 1, 1978, 00:00:00" is, as per your private response, January 1, 1978, 00:00:00 *local* time, then if you want to implement a UNIX-compatible version of time(), you need to convert the AmigaOS time to UTC, and then add 252460800 to the result. localtime(), in all implementations for UN*X, expects a UN*X-style time value to be passed to it; the tz implementation was originally an implementation for UN*X, so that's what it expects. So if you want to implement a time() that produces a result that can be passed to the tzcode implementation of localtime(), you need to implement a UN*X-compatible time().
The actual time is is number of seconds since 1.1.1978 and possibly a GMT offset (if the user have bothered to set it. The system does not take it into consideration). There is no concept of daylight saving rules and no concept of UTC.
I guess I need to determine the exact point of January 1, 1970, 00:00:00 *UTC* on my (AmigaOS) timeline in order to use the time.h functions in tz,
Correct.
and I assume the TZ variable and tz code can help me to do so.
The tz code was originally written for UN*X, so the conversions it's primarily oriented to implementing are: 1) convert a seconds-since-a-UTC-epoch value to year/month/day/hour/minute/second in local time (localtime()); 2) convert year/month/day/hour/minute/second in local time to a seconds-since-a-UTC-Epoch value (mtkime()). As such, the code doesn't directly help an attempt to convert a seconds-since-a-local-time-Epoch value to a seconds-since-a-UTC-epoch value. You could, I guess, convert the AmigaOS time to year/month/day/hour/minute/second in local time, and then hand it to mtkime().
On Oct 9, 2016, at 20:03, Guy Harris wrote:
On Oct 8, 2016, at 12:46 PM, Carsten Larsen <cs@innolan.dk> wrote:
AmigaOS uses an Epoch of January 1, 1978, 00:00:00 instead of January 1, 1970, 00:00:00 UTC. Time zone is not specified.
The Epoch difference is easy to calculate.
As "January 1, 1978, 00:00:00" is, as per your private response, January 1, 1978, 00:00:00 *local* time, then if you want to implement a UNIX-compatible version of time(), you need to convert the AmigaOS time to UTC, and then add 252460800 to the result.
localtime(), in all implementations for UN*X, expects a UN*X-style time value to be passed to it; the tz implementation was originally an implementation for UN*X, so that's what it expects.
So if you want to implement a time() that produces a result that can be passed to the tzcode implementation of localtime(), you need to implement a UN*X-compatible time().
The patch solves the time() returns *local time epoch*, *epoch offset*, problem. diff --git a/localtime.c b/localtime.c index 6c00c45..313f846 100644 --- a/localtime.c +++ b/localtime.c @@ -2259,10 +2259,22 @@ posix2time(time_t t) /* Convert from the underlying system's time_t to the ersatz time_tz, which is called 'time_t' in this file. */ +// Epoch is January 1, 1978 instead of January 1, 1970 +#define LOCAL_EPOCH_OFFSET 252460800 + time_t time(time_t *p) { + long zone; time_t r = sys_time(0); + +#ifdef LOCAL_EPOCH_OFFSET + if(lcl_is_set) { + zone = (daylight == 0 ? timezone : altzone); + time = (time_t)(tv.tv_secs + LOCAL_EPOCH_OFFSET + zone); + } +#endif + if (p) *p = r; return r; It is probably not general enough to be included in the tzcode but maybe it can inspire others. Thank you for helping me out. Kind regard Carsten Larsen
On Oct 8, 7:27pm, cs@innolan.dk (Carsten Larsen) wrote: -- Subject: [tz] Adapting localtime.c | Hello list | | I am trying to adapt the tz code to a local system without any timezone | database (AmigaOS). I got the code up and running and everything seems | to work as intended. But one thing about the code puzzles me. | | I need to implement "time_t time(time_t *p)" which is the very last part | of localtime.c. Should this code return time as local time or as GMT | time ? Because I cannot get the time calculations to work properly. | | I use tzsetwall() to guess the timezone from the systems locale zone | information (GMT+1, etc) and tzset() to load timezone from the TZ | environment variable. Should "time_t time(time_t *p)" try to compensate | if lclptr is set, or should it always just return the plain system time? | | I hope someone knows the answer and also thank you for any | clarifications on this issue. man 3 time does :-) The time() function returns the value of time in seconds since 0 hours, 0 minutes, 0 seconds, January 1, 1970, Coordinated Universal Time. christos
participants (8)
-
Brian Inglis -
Carsten Larsen -
christos@zoulas.com -
Guy Harris -
John Haxby -
Paul Eggert -
Random832 -
Robert Elz