tz
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2000 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1999 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1998 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1997 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1996 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1995 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1994 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1993 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1992 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1991 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1990 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1989 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1988 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1987 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1986 -----
- December
- November
- 4 participants
- 7517 discussions
The letter from "Andy J. Chichak" <chch(a)gateway.tiasur.tomsk.su> about
Tomsk prompted me to check the Russian time zone data more carefully.
Unfortunately it's a mess, as Shanks was published in 1991, a year
that saw chaos in Russian time zones. Though it's hard to know what
the correct rules are, it _is_ clear that the rules I submitted last
year to the tz database are incorrect, since I got lost with the
+1hour -1hour business and ended up omitting a timezone just west of
the Urals.
Given Chichak's comments about being N hours away from Moscow, I
decided that the most likely possibility is that Russia kept in synch
with Moscow (for which we already have a detailed post-1991 update
from "Andrew A. Chernov" <ache(a)astral.msk.su>). I'd guess also that
Belarus followed suit, but (as described below) we know that Ukraine
did not, so I'd guess the other western bits of the ex-Soviet Union
stuck with EET instead of Moscow time. We have no data on Central
Asia and the Caucausus, so I'd guess we should stick with the pre-1991
rules for it until we have more data.
The following proposed corrections insert that missing timezone (its
biggest city is Kuybyshev) and bump the remaining Russian timezones by
one; this gives the proper value for Tomsk and Novosibirsk as reported
by Chichak.
The latest _Economist_ reports that the Crimea, as part of its attempt
to break away from Ukraine, has switched from Kiev time to Moscow
time, so I've proposed another timezone entry Europe/Simferopol to
take this into account.
Also, more people seem to be calling Macedonia ``Macedonia'' instead
of the odd ``The Former Yugoslav Republic of Macedonia'' moniker that
was first pasted on it, so I think we should call it by its common
name.
Finally, there is a minor typo in the Bahamas entry.
===================================================================
RCS file: RCS/northamerica,v
retrieving revision 1994.4
retrieving revision 1994.4.1.1
diff -c -r1994.4 -r1994.4.1.1
*** northamerica 1994/02/07 14:57:50 1994.4
--- northamerica 1994/05/29 04:38:57 1994.4.1.1
***************
*** 629,635 ****
# Bahamas
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
! Rule Bahamas 1912 max - Mar 2 0:00 0 S
Rule Bahamas 1964 max - Oct lastSun 2:00 0 S
Rule Bahamas 1964 1986 - Apr lastSun 2:00 1:00 D
Rule Bahamas 1987 max - Apr Sun>=1 2:00 1:00 D
--- 629,635 ----
# Bahamas
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
! Rule Bahamas 1912 only - Mar 2 0:00 0 S
Rule Bahamas 1964 max - Oct lastSun 2:00 0 S
Rule Bahamas 1964 1986 - Apr lastSun 2:00 1:00 D
Rule Bahamas 1987 max - Apr Sun>=1 2:00 1:00 D
===================================================================
RCS file: RCS/asia,v
retrieving revision 1994.4
retrieving revision 1994.4.1.1
diff -c -r1994.4 -r1994.4.1.1
*** asia 1994/02/07 14:57:49 1994.4
--- asia 1994/05/29 04:38:57 1994.4.1.1
***************
*** 29,39 ****
# 4:00 BSK BSD Baku*
# 4:00 GST GDT Gulf*
# 4:30 AFT Afghanistan*
! # 5:00 TSK TSD Tashkent*
# 5:00 PKT Pakistan*
# 5:30 IST IST India
# 5:45 NPT Nepal*
# 6:00 BGT Bengal, Bangladesh*
# 6:30 BMT Burma*
# 7:00 ICT Indochina*
# 7:00 JVT Java*
--- 29,40 ----
# 4:00 BSK BSD Baku*
# 4:00 GST GDT Gulf*
# 4:30 AFT Afghanistan*
! # 5:00 ASK ASD Ashkhabad*
# 5:00 PKT Pakistan*
# 5:30 IST IST India
# 5:45 NPT Nepal*
# 6:00 BGT Bengal, Bangladesh*
+ # 6:00 TSK TSD Tashkent*
# 6:30 BMT Burma*
# 7:00 ICT Indochina*
# 7:00 JVT Java*
***************
*** 60,72 ****
###############################################################################
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Russia 1981 1984 - Apr 1 0:00 1:00 D
Rule Russia 1981 1983 - Oct 1 0:00 0 K
! Rule Russia 1984 1990 - Sep lastSun 3:00 0 K
! Rule Russia 1985 1990 - Mar lastSun 2:00 1:00 D
! Rule Russia 1992 max - Sep lastSun 2:00s 0 K
! Rule Russia 1992 max - Mar lastSun 2:00s 1:00 D
# Afghanistan
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
--- 61,74 ----
###############################################################################
+ # From Paul Eggert <eggert(a)twinsun.com> (May 28, 1994):
+ # We don't know what happened to the clocks in the Caucausus and the ex-Soviet
+ # Central Asia after 1990. Until we get more info, stick with the pre-1991 rules.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Russia 1981 1984 - Apr 1 0:00 1:00 D
Rule Russia 1981 1983 - Oct 1 0:00 0 K
! Rule Russia 1984 max - Sep lastSun 3:00 0 K
! Rule Russia 1985 max - Mar lastSun 2:00 1:00 D
# Afghanistan
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
***************
*** 78,92 ****
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Yerevan 2:58:00 - LMT 1924 May 2
3:00 - MSK 1957 Mar
! 4:00 Russia BS%s 1991 Sep 29 3:00
! 3:00 Russia MS%s
# Azerbaijan
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Baku 3:19:24 - LMT 1924 May 2
3:00 - MSK 1957 Mar
! 4:00 Russia BS%s 1991 Sep 29 3:00
! 3:00 Russia MS%s
# Bahrain
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
--- 80,92 ----
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Yerevan 2:58:00 - LMT 1924 May 2
3:00 - MSK 1957 Mar
! 4:00 Russia BS%s
# Azerbaijan
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Baku 3:19:24 - LMT 1924 May 2
3:00 - MSK 1957 Mar
! 4:00 Russia BS%s
# Bahrain
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
***************
*** 277,284 ****
Zone Asia/Tbilisi 2:59:16 - LMT 1880
2:59 - LST 1924 May 2
3:00 - MSK 1957 Mar
! 4:00 Russia BS%s 1991 Sep 29 3:00
! 3:00 Russia MS%s
# India
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
--- 277,283 ----
Zone Asia/Tbilisi 2:59:16 - LMT 1880
2:59 - LST 1924 May 2
3:00 - MSK 1957 Mar
! 4:00 Russia BS%s
# India
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
***************
*** 516,523 ****
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Almaty 5:07:48 - LMT 1924 May 2
5:00 - TSK 1957 Mar
! 6:00 Russia TS%s 1991 Sep 29 3:00
! 5:00 Russia TS%s
###############################################################################
--- 515,521 ----
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Almaty 5:07:48 - LMT 1924 May 2
5:00 - TSK 1957 Mar
! 6:00 Russia TS%s
###############################################################################
***************
*** 565,572 ****
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Frunze 4:58:24 - LMT 1924 May 2
5:00 - TSK 1957 Mar
! 6:00 Russia TS%s 1991 Sep 29 3:00
! 5:00 Russia TS%s
# Laos
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
--- 563,569 ----
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Frunze 4:58:24 - LMT 1924 May 2
5:00 - TSK 1957 Mar
! 6:00 Russia TS%s
# Laos
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
***************
*** 755,762 ****
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Dushanbe 4:35:12 - LMT 1924 May 2
5:00 - TSK 1957 Mar
! 6:00 Russia TS%s 1991 Sep 29 3:00
! 5:00 Russia TS%s
# Thailand
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
--- 752,758 ----
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Dushanbe 4:35:12 - LMT 1924 May 2
5:00 - TSK 1957 Mar
! 6:00 Russia TS%s
# Thailand
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
***************
*** 767,775 ****
# Turkmenistan
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Ashkhabad 3:53:32 - LMT 1924 May 2
! 4:00 - BSK 1957 Mar
! 5:00 Russia SS%s 1991 Sep 29 3:00
! 4:00 Russia BS%s
# United Arab Emirates
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
--- 763,770 ----
# Turkmenistan
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Ashkhabad 3:53:32 - LMT 1924 May 2
! 4:00 - ASK 1957 Mar
! 5:00 Russia AS%s
# United Arab Emirates
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
***************
*** 780,787 ****
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Tashkent 4:37:12 - LMT 1924 May 2
5:00 - TSK 1957 Mar
! 6:00 Russia TS%s 1991 Sep 29 3:00
! 5:00 Russia TS%s
# Vietnam
# From Paul Eggert <eggert(a)twinsun.com> (November 18, 1993):
--- 775,781 ----
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Tashkent 4:37:12 - LMT 1924 May 2
5:00 - TSK 1957 Mar
! 6:00 Russia TS%s
# Vietnam
# From Paul Eggert <eggert(a)twinsun.com> (November 18, 1993):
===================================================================
RCS file: RCS/europe,v
retrieving revision 1994.4
retrieving revision 1994.4.1.1
diff -c -r1994.4 -r1994.4.1.1
*** europe 1994/02/07 14:57:50 1994.4
--- europe 1994/05/29 04:38:57 1994.4.1.1
***************
*** 32,46 ****
# 2:00 EET+DST Eastern Europe
# 3:00 MSK MSD Moscow
# 3:00 TUR+DST Turkey (no longer used)*
! # 4:00 ESK ESD Yekaterinburg*
! # 5:00 OSK OSD Omsk*
! # 6:00 NSK NSD Novosibirsk
! # 7:00 ISK ISD Irkutsk*
! # 8:00 YSK YSD Yakutsk*
! # 9:00 VSK VSD Vladivostok*
! # 10:00 GSK GSD Magadan*
! # 11:00 PSK PSD Petropavlovsk-Kamchatski*
! # 12:00 ASK ASD Anadyr*
#
# See the `africa' file for Zone naming conventions.
#
--- 32,47 ----
# 2:00 EET+DST Eastern Europe
# 3:00 MSK MSD Moscow
# 3:00 TUR+DST Turkey (no longer used)*
! # 4:00 KSK KSD Kuybyshev*
! # 5:00 ESK ESD Yekaterinburg*
! # 6:00 OSK OSD Omsk*
! # 7:00 NSK NSD Novosibirsk
! # 8:00 ISK ISD Irkutsk*
! # 9:00 YSK YSD Yakutsk*
! # 10:00 VSK VSD Vladivostok*
! # 11:00 GSK GSD Magadan*
! # 12:00 PSK PSD Petropavlovsk-Kamchatski*
! # 13:00 ASK ASD Anadyr*
#
# See the `africa' file for Zone naming conventions.
#
***************
*** 421,427 ****
# ## <years> is either a single year or a hyphen separated range, with --
# ## also accepted as I use this in TeX a lot.
# ## <start date> and <end date> are a digit followed bu a month name.
! # ## It is either an nth Saturday or an explcit date, depending on <flags>.
# ## 0 and/or none are used when there is no date, as during 1968--71.
# ## <flags> can contain `fixed' to indicate explicit dates and `double'
# ## to indicate double summer time dates are present.
--- 422,428 ----
# ## <years> is either a single year or a hyphen separated range, with --
# ## also accepted as I use this in TeX a lot.
# ## <start date> and <end date> are a digit followed bu a month name.
! # ## It is either an nth Saturday or an explicit date, depending on <flags>.
# ## 0 and/or none are used when there is no date, as during 1968--71.
# ## <flags> can contain `fixed' to indicate explicit dates and `double'
# ## to indicate double summer time dates are present.
***************
*** 730,739 ****
Rule Russia 1921 only - Oct 1 0:00 0 K
Rule Russia 1981 1984 - Apr 1 0:00 1:00 D
Rule Russia 1981 1983 - Oct 1 0:00 0 K
! Rule Russia 1984 1990 - Sep lastSun 2:00s 0 K
! Rule Russia 1985 1990 - Mar lastSun 2:00s 1:00 D
! Rule Russia 1992 max - Sep lastSun 2:00s 0 K
! Rule Russia 1992 max - Mar lastSun 2:00s 1:00 D
# These are for backward compatibility with older versions.
--- 731,738 ----
Rule Russia 1921 only - Oct 1 0:00 0 K
Rule Russia 1981 1984 - Apr 1 0:00 1:00 D
Rule Russia 1981 1983 - Oct 1 0:00 0 K
! Rule Russia 1984 max - Sep lastSun 2:00s 0 K
! Rule Russia 1985 max - Mar lastSun 2:00s 1:00 D
# These are for backward compatibility with older versions.
***************
*** 813,820 ****
2:31 Russia LST%s 1919 Jul 1 2:00
3:00 Russia MS%s 1922 Oct
2:00 - EET 1930 Jun 21
! 3:00 Russia MS%s 1991 Sep 29 3:00
! 2:00 Russia MS%s
# Belgium
# Whitman and Shanks disagree; go with Shanks, usually.
--- 812,822 ----
2:31 Russia LST%s 1919 Jul 1 2:00
3:00 Russia MS%s 1922 Oct
2:00 - EET 1930 Jun 21
! 3:00 Russia MS%s 1991 Mar 31 2:00s
! # From Paul Eggert <eggert(a)twinsun.com> (May 28, 1994): A guess at recent dates:
! 2:00 1:00 "EET DST" 1991 Sep 29 2:00s
! 2:00 - EET 1992 Jan 19 2:00s
! 3:00 Russia MS%s
# Belgium
# Whitman and Shanks disagree; go with Shanks, usually.
***************
*** 966,973 ****
2:00 - EET 1940 Aug 6
3:00 - MSK 1941 Sep 15
1:00 M-Eur MET%s 1944 Sep 22
! 3:00 Russia MS%s 1989 Mar 26 2:00
! 2:00 M-Eur MET%s
# Finland
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
--- 968,976 ----
2:00 - EET 1940 Aug 6
3:00 - MSK 1941 Sep 15
1:00 M-Eur MET%s 1944 Sep 22
! 3:00 Russia MS%s 1989 Mar 26 2:00s
! 2:00 1:00 "EET DST" 1989 Sep 24 2:00s
! 2:00 M-Eur EET%s
# Finland
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
***************
*** 1162,1168 ****
# to the julian/gregorian calendar) over the period in question.
# the winter begins on the Saturday next before St. Luke's day
# (old style), or on St. Luke's day, if a Saturday.
! # St. Luke's day ought to be traceable from ecclesiatical sources. "old style"
# might be a reference to the Julian calendar as opposed to Gregorian, or it
# might mean something else (???). The Gregorian calendar was not introduced
# in Iceland until 1700.
--- 1165,1171 ----
# to the julian/gregorian calendar) over the period in question.
# the winter begins on the Saturday next before St. Luke's day
# (old style), or on St. Luke's day, if a Saturday.
! # St. Luke's day ought to be traceable from ecclesiastical sources. "old style"
# might be a reference to the Julian calendar as opposed to Gregorian, or it
# might mean something else (???). The Gregorian calendar was not introduced
# in Iceland until 1700.
***************
*** 1260,1267 ****
2:00 - EET 1940 Aug 5
3:00 - MSK 1941 Jul
1:00 M-Eur MET%s 1944 Aug 8
! 3:00 Russia MS%s 1991 Sep 29 3:00
! 2:00 M-Eur MET%s
# Liechtenstein
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
--- 1263,1271 ----
2:00 - EET 1940 Aug 5
3:00 - MSK 1941 Jul
1:00 M-Eur MET%s 1944 Aug 8
! 3:00 Russia MS%s 1991 Mar 31 2:00s
! 2:00 1:00 "EET DST" 1991 Sep 29 2:00s
! 2:00 M-Eur EET%s
# Liechtenstein
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
***************
*** 1280,1287 ****
1:00 - MET 1940 Aug 3
3:00 - MSK 1941 Jun 24
1:00 M-Eur MET%s 1944 Aug
! 3:00 Russia MS%s 1991 Sep 29 3:00
! 2:00 M-Eur MET%s
# Luxembourg
# Whitman disagrees with most of these dates in minor ways; go with Shanks.
--- 1284,1292 ----
1:00 - MET 1940 Aug 3
3:00 - MSK 1941 Jun 24
1:00 M-Eur MET%s 1944 Aug
! 3:00 Russia MS%s 1991 Mar 31 2:00s
! 2:00 1:00 "EET DST" 1991 Sep 29 2:00s
! 2:00 M-Eur EET%s
# Luxembourg
# Whitman disagrees with most of these dates in minor ways; go with Shanks.
***************
*** 1319,1325 ****
1:00 Belgium MET%s 1979 Apr 1 2:00
1:00 M-Eur MET%s
! # The Former Yugoslav Republic of Macedonia
# They switched from the Julian to the Gregorian calendar on 1918 Mar 18.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Skopje 1:25:44 - LMT 1884
--- 1324,1330 ----
1:00 Belgium MET%s 1979 Apr 1 2:00
1:00 M-Eur MET%s
! # Macedonia
# They switched from the Julian to the Gregorian calendar on 1918 Mar 18.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Skopje 1:25:44 - LMT 1884
***************
*** 1351,1358 ****
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Chisinau 1:55:20 - LMT 1924 May 2
2:00 - EET 1930 Jun 21
! 3:00 - MSK 1981 Apr
! 3:00 Russia MS%s 1991 Sep 29 2:00s
2:00 M-Eur EET%s
# Monaco
--- 1356,1363 ----
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Chisinau 1:55:20 - LMT 1924 May 2
2:00 - EET 1930 Jun 21
! 3:00 Russia MS%s 1991 Mar 31 2:00s
! 2:00 1:00 "EET DST" 1991 Sep 29 2:00s
2:00 M-Eur EET%s
# Monaco
***************
*** 1435,1441 ****
Rule Poland 1919 only - Apr 15 2:00s 1:00 " DST"
# Whitman gives 1944 Nov 30; go with Shanks.
Rule Poland 1944 only - Oct 4 2:00 0 -
! # For 1944-1948 Whitman gives the previous day; go with SHanks.
Rule Poland 1945 only - Apr 29 0:00 1:00 " DST"
Rule Poland 1945 only - Nov 1 0:00 0 -
Rule Poland 1946 only - Apr 14 0:00 1:00 " DST"
--- 1440,1446 ----
Rule Poland 1919 only - Apr 15 2:00s 1:00 " DST"
# Whitman gives 1944 Nov 30; go with Shanks.
Rule Poland 1944 only - Oct 4 2:00 0 -
! # For 1944-1948 Whitman gives the previous day; go with Shanks.
Rule Poland 1945 only - Apr 29 0:00 1:00 " DST"
Rule Poland 1945 only - Nov 1 0:00 0 -
Rule Poland 1946 only - Apr 14 0:00 1:00 " DST"
***************
*** 1574,1647 ****
2:00 M-Eur EET%s
# Russia
! # From Paul Eggert <eggert(a)twinsun.com> (November 18, 1993):
# Moscow and Novosibirsk time zone names, and Moscow rules after 1991,
# are from Andrew A. Chernov <ache(a)astral.msk.su>.
! # I invented the other time zone names.
! # The rest is from Shanks; it's probably wrong after 1991.
! # We're not sure whether St Petersburg switched in step with Moscow after 1991;
! # it might be a useless name, so we'll comment it out for now.
#
# From Shanks (1991):
# Western Russia switched from the Julian to the Gregorian calendar
! # on 1918 Jan 14. Eatern Russia switched on 1920 Mar 18.
# In 1929 the Soviet Union instituted a 5 day week; in 1932 it instituted
# a 6 day week; on 1940 Jun 27 it returned to the Gregorian week.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
! #Zone Europe/St_Petersburg 2:30:20 - LMT 1880
! # 2:01 Russia LST%s 1919 Jul 1 2:00
! # 3:00 Russia MS%s 1922 Oct
! # 2:00 - EET 1930 Jun 21
! # 3:00 Russia MS%s 1991 Sep 29 3:00
! # 2:00 Russia SPS%s
! Zone Europe/Moscow 2:30:20 - LMT 1880
! 2:31 Russia LST%s 1919 Jul 1 2:00
! 3:00 Russia MS%s 1922 Oct
! 2:00 - EET 1930 Jun 21
! 3:00 Russia MS%s 1991 Mar lastSun 2:00s
! 2:00 1:00 "EET DST" 1991 Sep lastSun 2:00s
! 2:00 - EET 1992 Jan 19 2:00s
! 3:00 Russia MS%s
! Zone Asia/Yekaterinburg 4:02:34 - LMT 1924 May 2
! 4:00 - ESK 1957 Mar
! 5:00 Russia ES%s 1991 Sep 29 3:00
! 4:00 Russia ES%s
! Zone Asia/Omsk 4:53:36 - LMT 1924 May 2
! 5:00 - TSK 1957 Mar
! 6:00 Russia TS%s 1991 Sep 29 3:00
! 5:00 Russia OS%s
! Zone Asia/Novosibirsk 5:31:40 - LMT 1924 May 2
! 6:00 - NSK 1957 Mar
! 7:00 Russia NS%s 1991 Sep 29 3:00
! 6:00 Russia NS%s
! Zone Asia/Irkutsk 6:57:20 - LMT 1880
! 6:57 - LST 1924 May 2
! 7:00 - ISK 1957 Mar
! 8:00 Russia IS%s 1991 Sep 29 3:00
! 7:00 Russia IS%s
! Zone Asia/Yakutsk 8:38:40 - LMT 1924 May 2
! 8:00 - YSK 1957 Mar
! 9:00 Russia YS%s 1991 Sep 29 3:00
! 8:00 Russia YS%s
! Zone Asia/Vladivostok 8:47:44 - LMT 1880
! 8:48 - LST 1924 May 2
! 9:00 - VSK 1957 Mar
! 10:00 Russia VS%s 1991 Sep 29 3:00
! 9:00 Russia VS%s
# MSK is taken; settle for GSK.
Zone Asia/Magadan 10:03:12 - LMT 1924 May 2
10:00 - GSK 1957 Mar
! 11:00 Russia GS%s 1991 Sep 29 3:00
! 10:00 Russia GS%s
# This name should be Asia/Petropavlovsk-Kamchatski, but that's too long.
Zone Asia/Kamchatka 10:34:36 - LMT 1924 May 2
11:00 - PSK 1957 Mar
! 12:00 Russia PS%s 1991 Sep 29 3:00
! 11:00 Russia PS%s
Zone Asia/Anadyr 11:49:56 - LMT 1924 May 2
12:00 - ASK 1957 Mar
! 13:00 Russia AS%s 1991 Sep 29 3:00
! 12:00 Russia AS%s
# Serbia
# They switched from the Julian to the Gregorian calendar on 1918 Mar 18.
--- 1579,1669 ----
2:00 M-Eur EET%s
# Russia
! # From Paul Eggert <eggert(a)twinsun.com> (May 28, 1994):
# Moscow and Novosibirsk time zone names, and Moscow rules after 1991,
# are from Andrew A. Chernov <ache(a)astral.msk.su>.
! # I invented the other time zone names, and (unless otherwise specified)
! # guessed what happened after 1991; the clocks were chaotic, and we know little.
! # The rest is from Shanks.
#
# From Shanks (1991):
# Western Russia switched from the Julian to the Gregorian calendar
! # on 1918 Jan 14. Eastern Russia switched on 1920 Mar 18.
# In 1929 the Soviet Union instituted a 5 day week; in 1932 it instituted
# a 6 day week; on 1940 Jun 27 it returned to the Gregorian week.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
! Zone Europe/Moscow 2:30:20 - LMT 1880
! 2:31 Russia LST%s 1919 Jul 1 2:00
! 3:00 Russia MS%s 1922 Oct
! 2:00 - EET 1930 Jun 21
! 3:00 Russia MS%s 1991 Mar 31 2:00s
! 2:00 1:00 "EET DST" 1991 Sep 29 2:00s
! 2:00 - EET 1992 Jan 19 2:00s
! 3:00 Russia MS%s
! Zone Europe/Kuybyshev 3:20:36 - LMT 1924 May 2
! 3:00 - KSK 1957 Mar
! 4:00 Russia KS%s 1991 Mar 31 2:00s
! 3:00 1:00 KSD 1991 Sep 29 2:00s
! 3:00 - KSK 1992 Jan 19 2:00s
! 4:00 Russia KS%s
! Zone Asia/Yekaterinburg 4:02:34 - LMT 1924 May 2
! 4:00 - SSK 1957 Mar
! 5:00 Russia SS%s 1991 Mar 31 2:00s
! 4:00 1:00 SSD 1991 Sep 29 2:00s
! 4:00 - SSK 1992 Jan 19 2:00s
! 5:00 Russia ES%s # name change from Sverdlovsk
! Zone Asia/Omsk 4:53:36 - LMT 1924 May 2
! 5:00 - OSK 1957 Mar
! 6:00 Russia OS%s 1991 Mar 31 2:00s
! 5:00 1:00 OSD 1991 Sep 29 2:00s
! 5:00 - OSK 1992 Jan 19 2:00s
! 6:00 Russia OS%s
! Zone Asia/Novosibirsk 5:31:40 - LMT 1924 May 2
! 6:00 - NSK 1957 Mar
! 7:00 Russia NS%s 1991 Mar 31 2:00s
! 6:00 1:00 NSD 1991 Sep 29 2:00s
! 6:00 - NSK 1992 Jan 19 2:00s
! 7:00 Russia NS%s
! Zone Asia/Irkutsk 6:57:20 - LMT 1880
! 6:57 - LST 1924 May 2
! 7:00 - ISK 1957 Mar
! 8:00 Russia IS%s 1991 Mar 31 2:00s
! 7:00 1:00 ISD 1991 Sep 29 2:00s
! 7:00 - ISK 1992 Jan 19 2:00s
! 8:00 Russia IS%s
! Zone Asia/Yakutsk 8:38:40 - LMT 1924 May 2
! 8:00 - YSK 1957 Mar
! 9:00 Russia YS%s 1991 Mar 31 2:00s
! 8:00 1:00 YSD 1991 Sep 29 2:00s
! 8:00 - YSK 1992 Jan 19 2:00s
! 9:00 Russia YS%s
! Zone Asia/Vladivostok 8:47:44 - LMT 1880
! 8:48 - LST 1924 May 2
! 9:00 - VSK 1957 Mar
! 10:00 Russia VS%s 1991 Mar 31 2:00s
! 9:00 1:00 VSD 1991 Sep 29 2:00s
! 9:00 - VSK 1992 Jan 19 2:00s
! 10:00 Russia VS%s
# MSK is taken; settle for GSK.
Zone Asia/Magadan 10:03:12 - LMT 1924 May 2
10:00 - GSK 1957 Mar
! 11:00 Russia GS%s 1991 Mar 31 2:00s
! 10:00 1:00 GSD 1991 Sep 29 2:00s
! 10:00 - GSK 1992 Jan 19 2:00s
! 11:00 Russia GS%s
# This name should be Asia/Petropavlovsk-Kamchatski, but that's too long.
Zone Asia/Kamchatka 10:34:36 - LMT 1924 May 2
11:00 - PSK 1957 Mar
! 12:00 Russia PS%s 1991 Mar 31 2:00s
! 11:00 1:00 PSD 1991 Sep 29 2:00s
! 11:00 - PSK 1992 Jan 19 2:00s
! 12:00 Russia PS%s
Zone Asia/Anadyr 11:49:56 - LMT 1924 May 2
12:00 - ASK 1957 Mar
! 13:00 Russia AS%s 1991 Mar 31 2:00s
! 12:00 1:00 ASD 1991 Sep 29 2:00s
! 12:00 - ASK 1992 Jan 19 2:00s
! 13:00 Russia AS%s
# Serbia
# They switched from the Julian to the Gregorian calendar on 1918 Mar 18.
***************
*** 1816,1827 ****
Rule Ukraine 1921 only - Sep 1 0:00 1:00 " DST"
Rule Ukraine 1921 only - Oct 1 0:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
! Zone Europe/Kiev 2:02:04 - LMT 1880
2:02 Russia LST%s 1919 Jul 1 2:00
2:02 Ukraine LST%s 1924 May 2
2:00 - EET 1930 Jun 21
3:00 Russia MS%s 1990 Jul 17
2:00 M-Eur EET%s
###############################################################################
--- 1838,1861 ----
Rule Ukraine 1921 only - Sep 1 0:00 1:00 " DST"
Rule Ukraine 1921 only - Oct 1 0:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
! Zone Europe/Kiev 2:02:04 - LMT 1880
2:02 Russia LST%s 1919 Jul 1 2:00
2:02 Ukraine LST%s 1924 May 2
2:00 - EET 1930 Jun 21
3:00 Russia MS%s 1990 Jul 17
2:00 M-Eur EET%s
+ Zone Europe/Simferopol 2:16:24 - LMT 1880
+ 2:08 Russia LST%s 1919 Jul 1 2:00
+ 2:08 Ukraine LST%s 1924 May 2
+ 2:00 - EET 1930 Jun 21
+ 3:00 Russia MS%s 1991 Mar 31 2:00s
+ 2:00 1:00 "EET DST" 1991 Sep 29 2:00s
+ # From Paul Eggert <eggert(a)twinsun.com> (May 28, 1994):
+ # Today's _Economist_ (p 45) reports that Crimea switched
+ # from Kiev to Moscow time sometime after the January elections.
+ # For now, we'll guess that there was a 2-hour leap forward on March 27.
+ 2:00 M-Eur EET%s 1994 Mar 27 2:00s
+ 3:00 Russia MS%s
###############################################################################
1
0
v28i034: strftime - strftime(3) and date(1) implementation, V6.1, Part01/01
by Monty Solomon May 12, 1994
by Monty Solomon May 12, 1994
May 12, 1994
FYI
Begin forwarded message:
Path: decwrl!vixie!vixie!not-for-mail
From: arnold(a)skeeve.atl.ga.us (Arnold Robbins)
Newsgroups: comp.sources.unix
Subject: v28i034: strftime - strftime(3) and date(1) implementation, V6.1, Part01/01
Date: 11 May 1994 22:11:06 -0700
Organization: Vixie Enterprises
Lines: 1303
Sender: vixie(a)vix.com
Approved: vixie(a)gw.home.vix.com
Nntp-Posting-Host: gw.home.vix.com
To: unix-sources(a)pa.dec.com
Submitted-By: arnold(a)skeeve.atl.ga.us (Arnold Robbins)
Posting-Number: Volume 28, Issue 34
Archive-Name: strftime-6.1/part01
In Volume 27, Issue 207 our moderator writes:
>[ this recurring package is the cleanest, nicest date(1) and strftime(3)
> i have ever seen, including all free or vendor systems. --vix ]
To which I can only say, "gosh, thanks!".
I had written:
> It seems to be an annual event, something in the circling of the stars
> overhead, that requires me to post this, at least once a year. (:-)
>
> I sincerely hope this will be it (at least 'til next year! :-)
Alas, it seems to be an annual event that shortly after posting my package,
I also post bug fixes. :-)
There are three main fixes here. 1) An update to the date.1 man page to
reflect that POSIX.2 is not in draft any more, 2) Yet another fix to
the %V code, and 3) Portability enhancements if there is no tm_zone
field in the struct tm.
Thanks to all who sent mail and helped me track down the ISO 8601 issues.
This is strftime 6.1. The package is small enough I'm just reposting the
whole thing.
Arnold Robbins -- The Basement Computer | Laundry increases
Internet: arnold(a)skeeve.ATL.GA.US | exponentially in the
UUCP: emory!skeeve!arnold | number of children.
Bitnet: Forget it. Get on a real network. | -- Miriam Robbins
------------------------- cut here ------------------------------------
#! /bin/sh
echo - 'README'
cat << 'EOF' > 'README'
Tue May 10 21:43:29 EDT 1994
This package implements the Posix 1003.2 date command, as a wrapper around
an extended version of the ANSI strftime(3) library routine.
Everything in it is public domain.
Arnold Robbins -- The Basement Computer | Laundry increases
Internet: arnold(a)skeeve.ATL.GA.US | exponentially in the
UUCP: { gatech, emory }!skeeve!arnold | number of children.
Bitnet: Forget it. Get on a real network. | -- Miriam Robbins
EOF
echo - 'Makefile'
cat << 'EOF' > 'Makefile'
# Makefile for PD date and strftime
SRCS= date.c strftime.c
OBJS= date.o strftime.o
DOCS= date.1 strftime.3
# Uncomment the define of HAVE_TZNAME if your system has the tzname[] array.
# Uncomment the define of TM_IN_SYS_TIME if struct tm is in <sys/time.h>.
# Uncomment the define of TM_ZONE if your struct tm has the tm_zone field.
CFLAGS= -O #-DHAVE_TZNAME #-DTM_IN_SYS_TIME #-DHAVE_TM_ZONE
date: $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $@
date.o: date.c
strftime.o: strftime.c
EOF
echo - 'date.c'
cat << 'EOF' > 'date.c'
/*
* date.c
*
* Public domain implementation of Posix 1003.2
* date command. Lets strftime() do the dirty work.
*
* Arnold Robbins
* arnold(a)skeeve.atl.ga.us
* April, 1991
*
* Bug fix courtesy of Chris Ritson (C.R.Ritson(a)newcastle.ac.uk)
* February, 1994.
*/
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
extern char *malloc();
extern size_t strftime();
extern int getopt();
extern int optind;
int
main(argc, argv)
int argc;
char **argv;
{
time_t clock;
struct tm *now;
int c, size, ret;
char *defhow = "%a %b %e %H:%M:%S %Z %Y";
char *howto = defhow;
char *buf;
while ((c = getopt(argc, argv, "u")) != -1)
switch (c) {
case 'u':
putenv("TZ=GMT0");
break;
default:
fprintf(stderr, "usage: %s [-u] [+format_str]\n",
argv[0]);
exit(1);
}
time(& clock);
now = localtime(& clock);
if (optind < argc && argv[optind][0] == '+')
howto = & argv[optind][1];
size = strlen(howto) * 10;
if (size < 26)
size = 26;
if ((buf = malloc(size)) == NULL) {
perror("not enough memory");
exit(1);
}
ret = strftime(buf, size, howto, now);
if (ret != 0)
printf("%s\n", buf);
else {
fprintf(stderr, "conversion failed\n");
exit(1);
}
exit(0);
}
EOF
echo - 'strftime.c'
cat << 'EOF' > 'strftime.c'
/*
* strftime.c
*
* Public-domain implementation of ANSI C library routine.
*
* It's written in old-style C for maximal portability.
* However, since I'm used to prototypes, I've included them too.
*
* If you want stuff in the System V ascftime routine, add the SYSV_EXT define.
* For extensions from SunOS, add SUNOS_EXT.
* For stuff needed to implement the P1003.2 date command, add POSIX2_DATE.
* For VMS dates, add VMS_EXT.
* For complete POSIX semantics, add POSIX_SEMANTICS.
*
* The code for %c, %x, and %X is my best guess as to what's "appropriate".
* This version ignores LOCALE information.
* It also doesn't worry about multi-byte characters.
* So there.
*
* This file is also shipped with GAWK (GNU Awk), gawk specific bits of
* code are included if GAWK is defined.
*
* Arnold Robbins
* January, February, March, 1991
* Updated March, April 1992
* Updated April, 1993
* Updated February, 1994
* Updated May, 1994
*
* Fixes from ado(a)elsie.nci.nih.gov
* February 1991, May 1992
* Fixes from Tor Lillqvist tml(a)tik.vtt.fi
* May, 1993
* Further fixes from ado(a)elsie.nci.nih.gov
* February 1994
*/
#ifndef GAWK
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#endif
#if defined(TM_IN_SYS_TIME) || ! defined(GAWK)
#include <sys/types.h>
#include <sys/time.h>
#endif
/* defaults: season to taste */
#define SYSV_EXT 1 /* stuff in System V ascftime routine */
#define SUNOS_EXT 1 /* stuff in SunOS strftime routine */
#define POSIX2_DATE 1 /* stuff in Posix 1003.2 date command */
#define VMS_EXT 1 /* include %v for VMS date format */
#ifndef GAWK
#define POSIX_SEMANTICS 1 /* call tzset() if TZ changes */
#endif
#if defined(POSIX2_DATE)
#if ! defined(SYSV_EXT)
#define SYSV_EXT 1
#endif
#if ! defined(SUNOS_EXT)
#define SUNOS_EXT 1
#endif
#endif
#if defined(POSIX2_DATE)
#define adddecl(stuff) stuff
#else
#define adddecl(stuff)
#endif
#undef strchr /* avoid AIX weirdness */
#ifndef __STDC__
#define const /**/
extern void *malloc();
extern void *realloc();
extern void tzset();
extern char *strchr();
extern char *getenv();
static int weeknumber();
adddecl(static int iso8601wknum();)
#else
extern void *malloc(unsigned count);
extern void *realloc(void *ptr, unsigned count);
extern void tzset(void);
extern char *strchr(const char *str, int ch);
extern char *getenv(const char *v);
static int weeknumber(const struct tm *timeptr, int firstweekday);
adddecl(static int iso8601wknum(const struct tm *timeptr);)
#endif
#ifdef __GNUC__
#define inline __inline__
#else
#define inline /**/
#endif
#define range(low, item, hi) max(low, min(item, hi))
#if !defined(OS2) && !defined(MSDOS) && defined(HAVE_TZNAME)
extern char *tzname[2];
extern int daylight;
#endif
/* min --- return minimum of two numbers */
#ifndef __STDC__
static inline int
min(a, b)
int a, b;
#else
static inline int
min(int a, int b)
#endif
{
return (a < b ? a : b);
}
/* max --- return maximum of two numbers */
#ifndef __STDC__
static inline int
max(a, b)
int a, b;
#else
static inline int
max(int a, int b)
#endif
{
return (a > b ? a : b);
}
/* strftime --- produce formatted time */
#ifndef __STDC__
size_t
strftime(s, maxsize, format, timeptr)
char *s;
size_t maxsize;
const char *format;
const struct tm *timeptr;
#else
size_t
strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr)
#endif
{
char *endp = s + maxsize;
char *start = s;
auto char tbuf[100];
int i;
static short first = 1;
#ifdef POSIX_SEMANTICS
static char *savetz = NULL;
static int savetzlen = 0;
char *tz;
#endif /* POSIX_SEMANTICS */
#ifndef HAVE_TM_ZONE
extern char *timezone();
struct timeval tv;
struct timezone zone;
#endif /* HAVE_TM_ZONE */
/* various tables, useful in North America */
static const char *days_a[] = {
"Sun", "Mon", "Tue", "Wed",
"Thu", "Fri", "Sat",
};
static const char *days_l[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday",
};
static const char *months_a[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
static const char *months_l[] = {
"January", "February", "March", "April",
"May", "June", "July", "August", "September",
"October", "November", "December",
};
static const char *ampm[] = { "AM", "PM", };
if (s == NULL || format == NULL || timeptr == NULL || maxsize == 0)
return 0;
/* quick check if we even need to bother */
if (strchr(format, '%') == NULL && strlen(format) + 1 >= maxsize)
return 0;
#ifndef POSIX_SEMANTICS
if (first) {
tzset();
first = 0;
}
#else /* POSIX_SEMANTICS */
tz = getenv("TZ");
if (first) {
if (tz != NULL) {
int tzlen = strlen(tz);
savetz = (char *) malloc(tzlen + 1);
if (savetz != NULL) {
savetzlen = tzlen + 1;
strcpy(savetz, tz);
}
}
tzset();
first = 0;
}
/* if we have a saved TZ, and it is different, recapture and reset */
if (tz && savetz && (tz[0] != savetz[0] || strcmp(tz, savetz) != 0)) {
i = strlen(tz) + 1;
if (i > savetzlen) {
savetz = (char *) realloc(savetz, i);
if (savetz) {
savetzlen = i;
strcpy(savetz, tz);
}
} else
strcpy(savetz, tz);
tzset();
}
#endif /* POSIX_SEMANTICS */
for (; *format && s < endp - 1; format++) {
tbuf[0] = '\0';
if (*format != '%') {
*s++ = *format;
continue;
}
again:
switch (*++format) {
case '\0':
*s++ = '%';
goto out;
case '%':
*s++ = '%';
continue;
case 'a': /* abbreviated weekday name */
if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6)
strcpy(tbuf, "?");
else
strcpy(tbuf, days_a[timeptr->tm_wday]);
break;
case 'A': /* full weekday name */
if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6)
strcpy(tbuf, "?");
else
strcpy(tbuf, days_l[timeptr->tm_wday]);
break;
#ifdef SYSV_EXT
case 'h': /* abbreviated month name */
#endif
case 'b': /* abbreviated month name */
if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11)
strcpy(tbuf, "?");
else
strcpy(tbuf, months_a[timeptr->tm_mon]);
break;
case 'B': /* full month name */
if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11)
strcpy(tbuf, "?");
else
strcpy(tbuf, months_l[timeptr->tm_mon]);
break;
case 'c': /* appropriate date and time representation */
sprintf(tbuf, "%s %s %2d %02d:%02d:%02d %d",
days_a[range(0, timeptr->tm_wday, 6)],
months_a[range(0, timeptr->tm_mon, 11)],
range(1, timeptr->tm_mday, 31),
range(0, timeptr->tm_hour, 23),
range(0, timeptr->tm_min, 59),
range(0, timeptr->tm_sec, 61),
timeptr->tm_year + 1900);
break;
case 'd': /* day of the month, 01 - 31 */
i = range(1, timeptr->tm_mday, 31);
sprintf(tbuf, "%02d", i);
break;
case 'H': /* hour, 24-hour clock, 00 - 23 */
i = range(0, timeptr->tm_hour, 23);
sprintf(tbuf, "%02d", i);
break;
case 'I': /* hour, 12-hour clock, 01 - 12 */
i = range(0, timeptr->tm_hour, 23);
if (i == 0)
i = 12;
else if (i > 12)
i -= 12;
sprintf(tbuf, "%02d", i);
break;
case 'j': /* day of the year, 001 - 366 */
sprintf(tbuf, "%03d", timeptr->tm_yday + 1);
break;
case 'm': /* month, 01 - 12 */
i = range(0, timeptr->tm_mon, 11);
sprintf(tbuf, "%02d", i + 1);
break;
case 'M': /* minute, 00 - 59 */
i = range(0, timeptr->tm_min, 59);
sprintf(tbuf, "%02d", i);
break;
case 'p': /* am or pm based on 12-hour clock */
i = range(0, timeptr->tm_hour, 23);
if (i < 12)
strcpy(tbuf, ampm[0]);
else
strcpy(tbuf, ampm[1]);
break;
case 'S': /* second, 00 - 61 */
i = range(0, timeptr->tm_sec, 61);
sprintf(tbuf, "%02d", i);
break;
case 'U': /* week of year, Sunday is first day of week */
sprintf(tbuf, "%02d", weeknumber(timeptr, 0));
break;
case 'w': /* weekday, Sunday == 0, 0 - 6 */
i = range(0, timeptr->tm_wday, 6);
sprintf(tbuf, "%d", i);
break;
case 'W': /* week of year, Monday is first day of week */
sprintf(tbuf, "%02d", weeknumber(timeptr, 1));
break;
case 'x': /* appropriate date representation */
sprintf(tbuf, "%s %s %2d %d",
days_a[range(0, timeptr->tm_wday, 6)],
months_a[range(0, timeptr->tm_mon, 11)],
range(1, timeptr->tm_mday, 31),
timeptr->tm_year + 1900);
break;
case 'X': /* appropriate time representation */
sprintf(tbuf, "%02d:%02d:%02d",
range(0, timeptr->tm_hour, 23),
range(0, timeptr->tm_min, 59),
range(0, timeptr->tm_sec, 61));
break;
case 'y': /* year without a century, 00 - 99 */
i = timeptr->tm_year % 100;
sprintf(tbuf, "%02d", i);
break;
case 'Y': /* year with century */
sprintf(tbuf, "%d", 1900 + timeptr->tm_year);
break;
case 'Z': /* time zone name or abbrevation */
#ifdef HAVE_TZNAME
i = (daylight && timeptr->tm_isdst); /* 0 or 1 */
strcpy(tbuf, tzname[i]);
#else
#ifdef HAVE_TM_ZONE
strcpy(tbuf, timeptr->tm_zone);
#else
gettimeofday(& tv, & zone);
strcpy(tbuf, timezone(zone.tz_minuteswest,
timeptr->tm_isdst));
#endif
#endif
break;
#ifdef SYSV_EXT
case 'n': /* same as \n */
tbuf[0] = '\n';
tbuf[1] = '\0';
break;
case 't': /* same as \t */
tbuf[0] = '\t';
tbuf[1] = '\0';
break;
case 'D': /* date as %m/%d/%y */
strftime(tbuf, sizeof tbuf, "%m/%d/%y", timeptr);
break;
case 'e': /* day of month, blank padded */
sprintf(tbuf, "%2d", range(1, timeptr->tm_mday, 31));
break;
case 'r': /* time as %I:%M:%S %p */
strftime(tbuf, sizeof tbuf, "%I:%M:%S %p", timeptr);
break;
case 'R': /* time as %H:%M */
strftime(tbuf, sizeof tbuf, "%H:%M", timeptr);
break;
case 'T': /* time as %H:%M:%S */
strftime(tbuf, sizeof tbuf, "%H:%M:%S", timeptr);
break;
#endif
#ifdef SUNOS_EXT
case 'k': /* hour, 24-hour clock, blank pad */
sprintf(tbuf, "%2d", range(0, timeptr->tm_hour, 23));
break;
case 'l': /* hour, 12-hour clock, 1 - 12, blank pad */
i = range(0, timeptr->tm_hour, 23);
if (i == 0)
i = 12;
else if (i > 12)
i -= 12;
sprintf(tbuf, "%2d", i);
break;
#endif
#ifdef VMS_EXT
case 'v': /* date as dd-bbb-YYYY */
sprintf(tbuf, "%02d-%3.3s-%4d",
range(1, timeptr->tm_mday, 31),
months_a[range(0, timeptr->tm_mon, 11)],
timeptr->tm_year + 1900);
for (i = 3; i < 6; i++)
if (islower(tbuf[i]))
tbuf[i] = toupper(tbuf[i]);
break;
#endif
#ifdef POSIX2_DATE
case 'C':
sprintf(tbuf, "%02d", (timeptr->tm_year + 1900) / 100);
break;
case 'E':
case 'O':
/* POSIX locale extensions, ignored for now */
goto again;
case 'V': /* week of year according ISO 8601 */
#if defined(GAWK) && defined(VMS_EXT)
{
extern int do_lint;
extern void warning();
static int warned = 0;
if (! warned && do_lint) {
warned = 1;
warning(
"conversion %%V added in P1003.2; for VMS style date, use %%v");
}
}
#endif
sprintf(tbuf, "%02d", iso8601wknum(timeptr));
break;
case 'u':
/* ISO 8601: Weekday as a decimal number [1 (Monday) - 7] */
sprintf(tbuf, "%d", timeptr->tm_wday == 0 ? 7 :
timeptr->tm_wday);
break;
#endif /* POSIX2_DATE */
default:
tbuf[0] = '%';
tbuf[1] = *format;
tbuf[2] = '\0';
break;
}
i = strlen(tbuf);
if (i) {
if (s + i < endp - 1) {
strcpy(s, tbuf);
s += i;
} else
return 0;
}
}
out:
if (s < endp && *format == '\0') {
*s = '\0';
return (s - start);
} else
return 0;
}
/* isleap --- is a year a leap year? */
#ifndef __STDC__
static int
isleap(year)
int year;
#else
static int
isleap(int year)
#endif
{
return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
}
#ifdef POSIX2_DATE
/* iso8601wknum --- compute week number according to ISO 8601 */
#ifndef __STDC__
static int
iso8601wknum(timeptr)
const struct tm *timeptr;
#else
static int
iso8601wknum(const struct tm *timeptr)
#endif
{
/*
* From 1003.2:
* If the week (Monday to Sunday) containing January 1
* has four or more days in the new year, then it is week 1;
* otherwise it is the highest numbered week of the previous
* (52 or 53) year, and the next week is week 1.
*
* ADR: This means if Jan 1 was Monday through Thursday,
* it was week 1, otherwise week 52 or 53.
*
* XPG4 erroneously included POSIX.2 rationale text in the
* main body of the standard. Thus it requires week 53.
*/
int weeknum, jan1day, diff;
/* get week number, Monday as first day of the week */
weeknum = weeknumber(timeptr, 1);
/*
* With thanks and tip of the hatlo to tml(a)tik.vtt.fi
*
* What day of the week does January 1 fall on?
* We know that
* (timeptr->tm_yday - jan1.tm_yday) MOD 7 ==
* (timeptr->tm_wday - jan1.tm_wday) MOD 7
* and that
* jan1.tm_yday == 0
* and that
* timeptr->tm_wday MOD 7 == timeptr->tm_wday
* from which it follows that. . .
*/
jan1day = timeptr->tm_wday - (timeptr->tm_yday % 7);
if (jan1day < 0)
jan1day += 7;
/*
* If Jan 1 was a Monday through Thursday, it was in
* week 1. Otherwise it was last year's highest week, which is
* this year's week 0.
*
* What does that mean?
* If Jan 1 was Monday, the week number is exactly right, it can
* never be 0.
* If it was Tuesday through Thursday, the weeknumber is one
* less than it should be, so we add one.
* Otherwise, Friday, Saturday or Sunday, the week number is
* OK, but if it is 0, it needs to be 52 or 53.
*/
switch (jan1day) {
case 1: /* Monday */
break;
case 2: /* Tuesday */
case 3: /* Wednedsday */
case 4: /* Thursday */
weeknum++;
break;
case 5: /* Friday */
case 6: /* Saturday */
case 0: /* Sunday */
if (weeknum == 0) {
#ifdef USE_BROKEN_XPG4
/* XPG4 (as of March 1994) says 53 unconditionally */
weeknum = 53;
#else
/* get week number of last week of last year */
struct tm dec31ly; /* 12/31 last year */
dec31ly = *timeptr;
dec31ly.tm_year--;
dec31ly.tm_mon = 11;
dec31ly.tm_mday = 31;
dec31ly.tm_wday = (jan1day == 0) ? 6 : jan1day - 1;
dec31ly.tm_yday = 364 + isleap(dec31ly.tm_year + 1900);
weeknum = iso8601wknum(& dec31ly);
#endif
}
break;
}
return weeknum;
}
#endif
/* weeknumber --- figure how many weeks into the year */
/* With thanks and tip of the hatlo to ado(a)elsie.nci.nih.gov */
#ifndef __STDC__
static int
weeknumber(timeptr, firstweekday)
const struct tm *timeptr;
int firstweekday;
#else
static int
weeknumber(const struct tm *timeptr, int firstweekday)
#endif
{
int wday = timeptr->tm_wday;
int ret;
if (firstweekday == 1) {
if (wday == 0) /* sunday */
wday = 6;
else
wday--;
}
ret = ((timeptr->tm_yday + 7 - wday) / 7);
if (ret < 0)
ret = 0;
return ret;
}
#if 0
/* ADR --- I'm loathe to mess with ado's code ... */
Date: Wed, 24 Apr 91 20:54:08 MDT
From: Michal Jaegermann <audfax!emory!vm.ucs.UAlberta.CA!NTOMCZAK>
To: arnold(a)audiofax.com
Hi Arnold,
in a process of fixing of strftime() in libraries on Atari ST I grabbed
some pieces of code from your own strftime. When doing that it came
to mind that your weeknumber() function compiles a little bit nicer
in the following form:
/*
* firstweekday is 0 if starting in Sunday, non-zero if in Monday
*/
{
return (timeptr->tm_yday - timeptr->tm_wday +
(firstweekday ? (timeptr->tm_wday ? 8 : 1) : 7)) / 7;
}
How nicer it depends on a compiler, of course, but always a tiny bit.
Cheers,
Michal
ntomczak(a)vm.ucs.ualberta.ca
#endif
#ifdef TEST_STRFTIME
/*
* NAME:
* tst
*
* SYNOPSIS:
* tst
*
* DESCRIPTION:
* "tst" is a test driver for the function "strftime".
*
* OPTIONS:
* None.
*
* AUTHOR:
* Karl Vogel
* Control Data Systems, Inc.
* vogelke(a)c-17igp.wpafb.af.mil
*
* BUGS:
* None noticed yet.
*
* COMPILE:
* cc -o tst -DTEST_STRFTIME strftime.c
*/
/* ADR: I reformatted this to my liking, and deleted some unneeded code. */
#ifndef NULL
#include <stdio.h>
#endif
#include <sys/time.h>
#include <string.h>
#define MAXTIME 132
/*
* Array of time formats.
*/
static char *array[] =
{
"(%%A) full weekday name, var length (Sunday..Saturday) %A",
"(%%B) full month name, var length (January..December) %B",
"(%%C) Century %C",
"(%%D) date (%%m/%%d/%%y) %D",
"(%%E) Locale extensions (ignored) %E",
"(%%H) hour (24-hour clock, 00..23) %H",
"(%%I) hour (12-hour clock, 01..12) %I",
"(%%M) minute (00..59) %M",
"(%%O) Locale extensions (ignored) %O",
"(%%R) time, 24-hour (%%H:%%M) %R",
"(%%S) second (00..61) %S",
"(%%T) time, 24-hour (%%H:%%M:%%S) %T",
"(%%U) week of year, Sunday as first day of week (00..53) %U",
"(%%V) week of year according to ISO 8601 %V",
"(%%W) week of year, Monday as first day of week (00..53) %W",
"(%%X) appropriate locale time representation (%H:%M:%S) %X",
"(%%Y) year with century (1970...) %Y",
"(%%Z) timezone (EDT), or blank if timezone not determinable %Z",
"(%%a) locale's abbreviated weekday name (Sun..Sat) %a",
"(%%b) locale's abbreviated month name (Jan..Dec) %b",
"(%%c) full date (Sat Nov 4 12:02:33 1989)%n%t%t%t %c",
"(%%d) day of the month (01..31) %d",
"(%%e) day of the month, blank-padded ( 1..31) %e",
"(%%h) should be same as (%%b) %h",
"(%%j) day of the year (001..366) %j",
"(%%k) hour, 24-hour clock, blank pad ( 0..23) %k",
"(%%l) hour, 12-hour clock, blank pad ( 0..12) %l",
"(%%m) month (01..12) %m",
"(%%p) locale's AM or PM based on 12-hour clock %p",
"(%%r) time, 12-hour (same as %%I:%%M:%%S %%p) %r",
"(%%u) ISO 8601: Weekday as decimal number [1 (Monday) - 7] %u",
"(%%v) VAX date (dd-bbb-YYYY) %v",
"(%%w) day of week (0..6, Sunday == 0) %w",
"(%%x) appropriate locale date representation %x",
"(%%y) last two digits of year (00..99) %y",
(char *) NULL
};
/* main routine. */
int
main(argc, argv)
int argc;
char **argv;
{
long time();
char *next;
char string[MAXTIME];
int k;
int length;
struct tm *tm;
long clock;
/* Call the function. */
clock = time((long *) 0);
tm = localtime(&clock);
for (k = 0; next = array[k]; k++) {
length = strftime(string, MAXTIME, next, tm);
printf("%s\n", string);
}
exit(0);
}
#endif /* TEST_STRFTIME */
EOF
echo - 'date.1'
cat << 'EOF' > 'date.1'
.TH DATE 1
.SH NAME
date \- write the date and time
.SH SYNOPSIS
.B date
[
.B \-u
] [
.RI + format
]
.SH DESCRIPTION
.I Date
writes the current date and time to the standard output.
It is intended to be compliant with the Posix
1003.2 Command Language and Utilities standard.
Therefore, it is purposely
.I not
usable by the super-user for setting the system time.
.LP
.I Date
accepts one option:
.TP
.B \-u
Perform operations as if the
.B TZ
environment variable was set to
.BR GMT0 .
.LP
If an argument to
.I date
is given that begins with a ``+'',
then the output is controlled by the contents of the rest of
the string. Normal text is output unmodified, while field descriptors
in the format string are substituted for.
.LP
The
.I date
program is essentially a wrapper around
.IR strftime (3);
see there for a description of the available formatting options.
.LP
If no format string is given, or if it does not begin with a ``+'',
then the default format of \fB"%a %b %e %H:%M:%S %Z %Y"\fR will
be used. This produces the traditional style of output, such as
``Sun Mar 17 10:32:47 EST 1991''.
.SH SEE ALSO
time(2), strftime(3), localtime(3)
.SH BUGS
This version only works for the POSIX locale.
.SH AUTHOR
.nf
Arnold Robbins
.sp
INTERNET: arnold(a)skeeve.atl.ga.us
UUCP: emory!skeeve!arnold
Phone: +1 404 248 9324
.fi
EOF
echo - 'strftime.3'
cat << 'EOF' > 'strftime.3'
.TH STRFTIME 3
.SH NAME
strftime \- generate formatted time information
.SH SYNOPSIS
.ft B
.nf
#include <sys/types.h>
#include <time.h>
.sp
size_t strftime(char *s, size_t maxsize, const char *format,
const struct tm *timeptr);
.SH DESCRIPTION
The following description is transcribed verbatim from the December 7, 1988
draft standard for ANSI C.
This draft is essentially identical in technical content
to the final version of the standard.
.LP
The
.B strftime
function places characters into the array pointed to by
.B s
as controlled by the string pointed to by
.BR format .
The format shall be a multibyte character sequence, beginning and ending in
its initial shift state.
The
.B format
string consists of zero or more conversion specifiers and ordinary
multibyte characters. A conversion specifier consists of a
.B %
character followed by a character that determines the behavior of the
conversion specifier.
All ordinary multibyte characters (including the terminating null
character) are copied unchanged into the array.
If copying takes place between objects that overlap the behavior is undefined.
No more than
.B maxsize
characters are placed into the array.
Each conversion specifier is replaced by appropriate characters as described
in the following list.
The appropriate characters are determined by the
.B LC_TIME
category of the current locale and by the values contained in the
structure pointed to by
.BR timeptr .
.TP
.B %a
is replaced by the locale's abbreviated weekday name.
.TP
.B %A
is replaced by the locale's full weekday name.
.TP
.B %b
is replaced by the locale's abbreviated month name.
.TP
.B %B
is replaced by the locale's full month name.
.TP
.B %c
is replaced by the locale's appropriate date and time representation.
.TP
.B %d
is replaced by the day of the month as a decimal number
.RB ( 01 - 31 ).
.TP
.B %H
is replaced by the hour (24-hour clock) as a decimal number
.RB ( 00 - 23 ).
.TP
.B %I
is replaced by the hour (12-hour clock) as a decimal number
.RB ( 01 - 12 ).
.TP
.B %j
is replaced by the day of the year as a decimal number
.RB ( 001 - 366 ).
.TP
.B %m
is replaced by the month as a decimal number
.RB ( 01 - 12 ).
.TP
.B %M
is replaced by the minute as a decimal number
.RB ( 00 - 59 ).
.TP
.B %p
is replaced by the locale's equivalent of the AM/PM designations associated
with a 12-hour clock.
.TP
.B %S
is replaced by the second as a decimal number
.RB ( 00 - 61 ).
.TP
.B %U
is replaced by the week number of the year (the first Sunday as the first
day of week 1) as a decimal number
.RB ( 00 - 53 ).
.TP
.B %w
is replaced by the weekday as a decimal number
.RB [ "0 " (Sunday)- 6 ].
.TP
.B %W
is replaced by the week number of the year (the first Monday as the first
day of week 1) as a decimal number
.RB ( 00 - 53 ).
.TP
.B %x
is replaced by the locale's appropriate date representation.
.TP
.B %X
is replaced by the locale's appropriate time representation.
.TP
.B %y
is replaced by the year without century as a decimal number
.RB ( 00 - 99 ).
.TP
.B %Y
is replaced by the year with century as a decimal number.
.TP
.B %Z
is replaced by the time zone name or abbreviation, or by no characters if
no time zone is determinable.
.TP
.B %%
is replaced by
.BR % .
.LP
If a conversion specifier is not one of the above, the behavior is
undefined.
.SH RETURNS
If the total number of resulting characters including the terminating null
character is not more than
.BR maxsize ,
the
.B strftime
function returns the number of characters placed into the array pointed to
by
.B s
not including the terminating null character.
Otherwise, zero is returned and the contents of the array are indeterminate.
.SH NON-ANSI EXTENSIONS
If
.B SYSV_EXT
is defined when the routine is compiled, then the following additional
conversions will be available.
These are borrowed from the System V
.IR cftime (3)
and
.IR ascftime (3)
routines.
.TP
.B %D
is equivalent to specifying
.BR %m/%d/%y .
.TP
.B %e
is replaced by the day of the month,
padded with a blank if it is only one digit.
.TP
.B %h
is equivalent to
.BR %b ,
above.
.TP
.B %n
is replaced with a newline character (\s-1ASCII LF\s+1).
.TP
.B %r
is equivalent to specifying
.BR "%I:%M:%S %p" .
.TP
.B %R
is equivalent to specifying
.BR %H:%M .
.TP
.B %T
is equivalent to specifying
.BR %H:%M:%S .
.TP
.B %t
is replaced with a \s-1TAB\s+1 character.
.PP
If
.B SUNOS_EXT
is defined when the routine is compiled, then the following additional
conversions will be available.
These are borrowed from the SunOS version of
.IR strftime .
.TP
.B %k
is replaced by the hour (24-hour clock) as a decimal number
.RB ( 0 - 23 ).
Single digit numbers are padded with a blank.
.TP
.B %l
is replaced by the hour (12-hour clock) as a decimal number
.RB ( 1 - 12 ).
Single digit numbers are padded with a blank.
.SH POSIX 1003.2 EXTENSIONS
If
.B POSIX2_DATE
is defined, then all of the conversions available with
.B SYSV_EXT
and
.B SUNOS_EXT
are available, as well as the
following additional conversions:
.TP
.B %C
The century, as a number between 00 and 99.
.TP
.B %u
is replaced by the weekday as a decimal number
.RB [ "1 " (Monday)- 7 ].
.TP
.B %V
is replaced by the week number of the year (the first Monday as the first
day of week 1) as a decimal number
.RB ( 01 - 53 ).
The method for determining the week number is as specified by ISO 8601
(to wit: if the week containing January 1 has four or more days in the
new year, then it is week 1, otherwise it is the highest numbered
week of the previous year (52 or 53)
and the next week is week 1).
.LP
The text of the POSIX standard for the
.I date
utility describes
.B %U
and
.B %W
this way:
.TP
.B %U
is replaced by the week number of the year (the first Sunday as the first
day of week 1) as a decimal number
.RB ( 00 - 53 ).
All days in a new year preceding the first Sunday are considered to be
in week 0.
.TP
.B %W
is replaced by the week number of the year (the first Monday as the first
day of week 1) as a decimal number
.RB ( 00 - 53 ).
All days in a new year preceding the first Monday are considered to be
in week 0.
.LP
In addition, the alternate representations
.BR %Ec ,
.BR %EC ,
.BR %Ex ,
.BR %Ey ,
.BR %EY ,
.BR %Od ,
.BR %Oe ,
.BR %OH ,
.BR %OI ,
.BR %Om ,
.BR %OM ,
.BR %OS ,
.BR %Ou ,
.BR %OU ,
.BR %OV ,
.BR %Ow ,
.BR %OW ,
and
.B %Oy
are recognized, but their normal representations are used.
.SH VMS EXTENSIONS
If
.B VMS_EXT
is defined, then the following additional conversion is available:
.TP
.B %v
The date in VMS format (e.g. 20-JUN-1991).
.SH SEE ALSO
.IR time (2),
.IR ctime (3),
.IR localtime (3),
.IR tzset (3)
.SH BUGS
This version does not handle multibyte characters or pay attention to the
setting of the
.B LC_TIME
environment variable.
.LP
It is not clear what is ``appropriate'' for the C locale; the values
returned are a best guess on the author's part.
.SH CAVEATS
The pre-processor symbol
.B POSIX_SEMANTICS
is automatically defined, which forces the code to call
.IR tzset (3)
whenever the
.B TZ
environment variable has changed.
If this routine will be used in an application that will not be changing
.BR TZ ,
then there may be some performance improvements by not defining
.BR POSIX_SEMANTICS .
.SH AUTHOR
.nf
Arnold Robbins
.sp
INTERNET: arnold(a)skeeve.atl.ga.us
UUCP: emory!skeeve!arnold
Phone: +1 404 248 9324
.fi
.SH ACKNOWLEDGEMENTS
Thanks to Geoff Clare <gwc(a)root.co.uk> for helping debug earlier
versions of this routine, and for advice about POSIX semantics.
Additional thanks to Arthur David Olsen <ado(a)elsie.nci.nih.gov>
for some code improvements.
Thanks also to Tor Lillqvist <tml(a)tik.vtt.fi>
for code fixes to the ISO 8601 code.
EOF
1
0
May 11, 1994
> ! /*
> ! ** The following is equivalent to `return asctime(localtime(timep));',
> ! ** except it does not modify localtime's static storage,
> ! ** and thus it works around all-too-common bugs like
> ! ** `struct tm *p = localtime(&t1); puts(ctime(&t2)); return p->tm_year'.
> ! */
Hmmm...given the X3J11 description of ctime in section 4.12.3.2...
The ctime funciton converts the calendar time pointed to by timer
to local time in the form of a string. It is equivalent to
asctime(localtime(timer))
...do we open ourselves up to standard conformance challenges if ctime is
anything except "asctime(localtime(timer))"?
--ado
2
1
May 8, 1994
The following Usenet article describes a extension to Posix TZ strings
that allows the strings to express the daylight savings time rules
currently used in Britain. At the end of this message is a patch to
the tz package that adds support for this extension.
This patch also fixes a theoretical leap second problem with Posix TZ
strings. But looking at the code, I suspect that leap seconds don't
work at all with Posix TZ strings; perhaps this is intentional?
Newsgroups: comp.unix.unixware
From: jjf(a)dsbc.icl.co.uk (J J Farrell)
Subject: Re: Daylight saving time in UW1.1
Message-ID: <CpCvnG.7Dy(a)dsbc.icl.co.uk>
Organization: International Computers Limited
References: <767043120.AA04204(a)cswamp.apana.org.au> <Cp9x6n.7uB(a)novell.co.uk>
Date: Fri, 6 May 1994 00:50:03 GMT
In article <Cp9x6n.7uB(a)novell.co.uk> msohnius(a)novell.co.uk
(Martin Sohnius) writes:
> UnixWare supports two different styles of timezone handling.
>
> One is what I may call "System V" style, with the TZ environment
> variable as described in environ(5).
It might be better described as "Standard" style - it's been specified
by X/Open for many years, and I think Posix is the same.
> Note also that the October rule for many parts of Australia
> ("next-to-last Sunday in October") cannot be implemented with the
> "System V" style TZ. (NB nor can the British rule,
> "day after 4th Saturday in October").
I'm not sure about the Australian ones, but the British rule can be
done in "System V" style TZ. The following works on SVR4 systems and
has been issued by ICL for several years:
GMT0BST,M3.5.0/1,M10.4.6/26
I've not looked up the wording in the SVR4 documentation, but this does
break the wording in XPG3; they may have loosened the wording in XPG4,
but I haven't checked.
It is probably a bug that this works, but bugs can sometimes be useful!
My opinions; I do not speak for my employer.
===================================================================
RCS file: RCS/localtime.c,v
retrieving revision 1994.6.1.2
retrieving revision 1994.6.1.3
diff -c -r1994.6.1.2 -r1994.6.1.3
*** localtime.c 1994/05/09 10:16:11 1994.6.1.2
--- localtime.c 1994/05/09 10:22:51 1994.6.1.3
***************
*** 414,423 ****
{
int num;
! strp = getnum(strp, &num, 0, HOURSPERDAY);
if (strp == NULL)
return NULL;
! *secsp = num * SECSPERHOUR;
if (*strp == ':') {
++strp;
strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
--- 414,429 ----
{
int num;
! /*
! ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
! ** "M10.4.6/26", which does not conform to Posix,
! ** but which specifies the equivalent of
! ** ``02:00 on the first Sunday on or after 23 Oct''.
! */
! strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
if (strp == NULL)
return NULL;
! *secsp = num * (long) SECSPERHOUR;
if (*strp == ':') {
++strp;
strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
***************
*** 426,432 ****
*secsp += num * SECSPERMIN;
if (*strp == ':') {
++strp;
! strp = getnum(strp, &num, 0, SECSPERMIN - 1);
if (strp == NULL)
return NULL;
*secsp += num;
--- 432,439 ----
*secsp += num * SECSPERMIN;
if (*strp == ':') {
++strp;
! /* `SECSPERMIN' allows for leap seconds. */
! strp = getnum(strp, &num, 0, SECSPERMIN);
if (strp == NULL)
return NULL;
*secsp += num;
1
0
workaround for common programming error involving ctime and localtime
by yata!eggertï¼ twinsun.com May 8, 1994
by yata!eggertï¼ twinsun.com May 8, 1994
May 8, 1994
The following patch lets the tz package work around
a common programming error when using ctime and localtime.
===================================================================
RCS file: RCS/localtime.c,v
retrieving revision 1994.6.1.1
retrieving revision 1994.6.1.2
diff -c -r1994.6.1.1 -r1994.6.1.2
*** localtime.c 1994/05/05 16:24:49 1994.6.1.1
--- localtime.c 1994/05/09 10:16:11 1994.6.1.2
***************
*** 1136,1142 ****
ctime(timep)
const time_t * const timep;
{
! return asctime(localtime(timep));
}
/*
--- 1136,1151 ----
ctime(timep)
const time_t * const timep;
{
! struct tm tm;
!
! /*
! ** The following is equivalent to `return asctime(localtime(timep));',
! ** except it does not modify localtime's static storage,
! ** and thus it works around all-too-common bugs like
! ** `struct tm *p = localtime(&t1); puts(ctime(&t2)); return p->tm_year'.
! */
! localsub(timep, 0L, &tm);
! return asctime(&tm);
}
/*
1
0
Here is a patch that adds support for locales to the tz package's
strftime function and date command. For example, if the LC_TIME
environment variable is set to "de", `date' will output something like
`Montag, 9. Mai 1994, 02:59:54 Uhr PDT' instead of the usual
`Mon May 9 02:59:54 PDT 1994'.
The locale files are in /usr/lib/locale, using the same format as in
Solaris 2.3 (which I assume is fairly standard, at least among SVR4-ish
hosts). If locale files are absent or are not of the proper form,
traditional behavior is assumed. I invented a strftime format `%+',
which expands to the default format used by `date'; this makes it
easier to put all the locale-relevant stuff in strftime.c, and also
lets the user type fun commands like `date "+|%+|"'.
This patch also extends strftime to use the format "%c" if its format
argument is (char*)0; this is the documented behavior in Solaris 2.3.
This patch assumes the Posix/GCC cleanup patch I sent a while back.
===================================================================
RCS file: RCS/Makefile,v
retrieving revision 1994.7.1.1
retrieving revision 1994.7.1.2
diff -c -r1994.7.1.1 -r1994.7.1.2
*** Makefile 1994/05/05 19:10:21 1994.7.1.1
--- Makefile 1994/05/09 09:47:26 1994.7.1.2
***************
*** 82,87 ****
--- 82,88 ----
# -DHAVE_ADJTIME=0 if `adjtime' does not exist (SVR0?)
# -DHAVE_LONG_DOUBLE if your compiler supports the `long double' type
# -DHAVE_MKDIR=0 if the mkdir system call does not work (SVR0?)
+ # -DHAVE_SETLOCALE=0 if the setlocale function does not work (SVR3)
# -DHAVE_SETTIMEOFDAY=0 if settimeofday does not exist (SVR0?)
# -DHAVE_SETTIMEOFDAY=1 if settimeofday has just 1 arg (SVR4)
# -DHAVE_SETTIMEOFDAY=2 if settimeofday uses 2nd arg (4.3BSD)
***************
*** 89,94 ****
--- 90,96 ----
# -DHAVE_STDLIB_H=0 if `#include <stdlib.h>' does not work
# -DHAVE_UMASK=0 if `umask(0)' does not work
# -DHAVE_UNISTD=0 if `#include <unistd.h>' does not work
+ # -DLOCALE_HOME=\"path\" if locales are in "path", not "/usr/lib/locale"
# -DNEED_STRCHR_DECL=1 if <string.h> does not declare strchr fully
# -DNEED_TIME_DECL=1 if <time.h> does not declare `time' fully
# -Dalloc_size_t=T if the malloc size argument is of type T, not size_t
===================================================================
RCS file: RCS/date.1,v
retrieving revision 1994.7
retrieving revision 1994.7.1.1
diff -c -r1994.7 -r1994.7.1.1
*** date.1 1992/11/04 18:08:06 1994.7
--- date.1 1994/05/09 09:47:50 1994.7.1.1
***************
*** 37,42 ****
--- 37,43 ----
(or by the abbreviation for the time zone specified in the
.B TZ
environment variable if set).
+ The exact output format depends on the locale.
.PP
If a command-line argument starts with a plus sign
.RB (` + '),
***************
*** 51,70 ****
to be output in a particular way
(or identify a special character to output):
.nf
.if t .in +.5i
.if n .in +2
! .ta \w'%M\0\0'u +\w'Wed Mar 8 14:54:40 1989\0\0'u
Sample output Explanation
! %a Wed Abbreviated weekday name
! %A Wednesday Full weekday name
! %b Mar Abbreviated month name
! %B March Full month name
! %c 03/08/89 14:54:40 Month/day/year Hour:minute:second
! %C Wed Mar 8 14:54:40 1989 a la \fIasctime\^\fP(3)
%d 08 Day of month (always two digits)
%D 03/08/89 Month/day/year (eight characters)
%e 8 Day of month (leading zero blanked)
! %h Mar Abbreviated month name
%H 14 24-hour-clock hour (two digits)
%I 02 12-hour-clock hour (two digits)
%j 067 Julian day number (three digits)
--- 52,72 ----
to be output in a particular way
(or identify a special character to output):
.nf
+ .sp
.if t .in +.5i
.if n .in +2
! .ta \w'%M\0\0'u +\w'Wed Mar 8 14:54:40 EST 1989\0\0'u
Sample output Explanation
! %a Wed Abbreviated weekday name*
! %A Wednesday Full weekday name*
! %b Mar Abbreviated month name*
! %B March Full month name*
! %c Wed Mar 08 14:54:40 1989 Date and time*
! %C 19 Century
%d 08 Day of month (always two digits)
%D 03/08/89 Month/day/year (eight characters)
%e 8 Day of month (leading zero blanked)
! %h Mar Abbreviated month name*
%H 14 24-hour-clock hour (two digits)
%I 02 12-hour-clock hour (two digits)
%j 067 Julian day number (three digits)
***************
*** 82,94 ****
%U 10 Sunday-based week number (two digits)
%w 3 Day number (one digit, Sunday is 0)
%W 10 Monday-based week number (two digits)
! %x 03/08/89 Month/day/year (eight characters)
! %X 14:54:40 Hour:minute:second
%y 89 Last two digits of year
%Y 1989 Year in full
%Z EST Time zone abbreviation
.if t .in -.5i
.if n .in -2
.fi
If a character other than one of those shown above appears after
a percent sign in the format,
--- 84,99 ----
%U 10 Sunday-based week number (two digits)
%w 3 Day number (one digit, Sunday is 0)
%W 10 Monday-based week number (two digits)
! %x 03/08/89 Date*
! %X 14:54:40 Time*
%y 89 Last two digits of year
%Y 1989 Year in full
%Z EST Time zone abbreviation
+ %+ Wed Mar 8 14:54:40 EST 1989 Default output format*
.if t .in -.5i
.if n .in -2
+ * The exact output depends on the locale.
+ .sp
.fi
If a character other than one of those shown above appears after
a percent sign in the format,
***************
*** 150,153 ****
--- 155,175 ----
On BSD-based systems,
the adjustment is made by changing the rate at which time advances;
on System-V-based systems, the adjustment is made by changing the time.
+ .SH FILES
+ .ta \w'/usr/local/etc/zoneinfo/posixrules\0\0'u
+ /usr/lib/locale/\f2L\fP/LC_TIME description of time locale \f2L\fP
+ .br
+ /usr/local/etc/zoneinfo time zone information directory
+ .br
+ /usr/local/etc/zoneinfo/localtime local time zone file
+ .br
+ /usr/local/etc/zoneinfo/posixrules used with POSIX-style TZ's
+ .br
+ /usr/local/etc/zoneinfo/GMT for UTC leap seconds
+ .sp
+ If
+ .B /usr/local/etc/zoneinfo/GMT
+ is absent,
+ UTC leap seconds are loaded from
+ .BR /usr/local/etc/zoneinfo/posixrules .
.\" @(#)date.1 7.2
===================================================================
RCS file: RCS/date.c,v
retrieving revision 1994.6.1.1
retrieving revision 1994.6.1.2
diff -c -r1994.6.1.1 -r1994.6.1.2
*** date.c 1994/05/05 16:24:49 1994.6.1.1
--- date.c 1994/05/09 09:47:28 1994.6.1.2
***************
*** 40,45 ****
--- 40,49 ----
#endif
#include "utmp.h" /* for OLD_TIME (or its absence) */
+ #if HAVE_SETLOCALE
+ # include "locale.h"
+ #endif
+
/*
** The two things date knows about time are. . .
*/
***************
*** 485,495 ****
(void) time(&now);
tm = *localtime(&now);
! if (format == NULL) {
! timeout(stdout, "%a %b ", &tm);
! (void) printf("%2d ", tm.tm_mday);
! timeout(stdout, "%X %Z %Y", &tm);
! } else timeout(stdout, format, &tm);
(void) putchar('\n');
(void) fflush(stdout);
(void) fflush(stderr);
--- 489,498 ----
(void) time(&now);
tm = *localtime(&now);
! #if HAVE_SETLOCALE
! setlocale(LC_TIME, "");
! #endif
! timeout(stdout, format ? format : "%+", &tm);
(void) putchar('\n');
(void) fflush(stdout);
(void) fflush(stderr);
===================================================================
RCS file: RCS/private.h,v
retrieving revision 1994.5.1.1
retrieving revision 1994.5.1.2
diff -c -r1994.5.1.1 -r1994.5.1.2
*** private.h 1994/04/03 02:54:41 1994.5.1.1
--- private.h 1994/05/09 09:47:28 1994.5.1.2
***************
*** 30,35 ****
--- 30,38 ----
#ifndef HAVE_MKDIR
#define HAVE_MKDIR 1
#endif
+ #ifndef HAVE_SETLOCALE
+ #define HAVE_SETLOCALE 1
+ #endif
#ifndef HAVE_SETTIMEOFDAY
#define HAVE_SETTIMEOFDAY 3
#endif
***************
*** 48,53 ****
--- 51,60 ----
#endif
#ifndef NEED_TIME_DECL
#define NEED_TIME_DECL 0
+ #endif
+
+ #ifndef LOCALE_HOME
+ #define LOCALE_HOME "/usr/lib/locale"
#endif
/*
===================================================================
RCS file: RCS/strftime.c,v
retrieving revision 1994.6
retrieving revision 1994.6.1.1
diff -c -r1994.6 -r1994.6.1.1
*** strftime.c 1994/05/05 15:47:58 1994.6
--- strftime.c 1994/05/09 09:48:02 1994.6.1.1
***************
*** 3,10 ****
static char elsieid[] = "@(#)strftime.c 7.19";
/*
** Based on the UCB version with the ID appearing below.
! ** This is ANSIish only when time is treated identically in all locales and
! ** when "multibyte character == plain character".
*/
#endif /* !defined NOID */
#endif /* !defined lint */
--- 3,9 ----
static char elsieid[] = "@(#)strftime.c 7.19";
/*
** Based on the UCB version with the ID appearing below.
! ** This is ANSIish only when "multibyte character == plain character".
*/
#endif /* !defined NOID */
#endif /* !defined lint */
***************
*** 35,60 ****
#endif /* !defined LIBC_SCCS */
#include "tzfile.h"
! static const char afmt[][4] = {
! "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
! static const char Afmt[][10] = {
! "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
! "Saturday"
! };
! static const char bfmt[][4] = {
! "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
! "Oct", "Nov", "Dec"
! };
! static const char Bfmt[][10] = {
! "January", "February", "March", "April", "May", "June", "July",
! "August", "September", "October", "November", "December"
};
static char *_add P((const char *, char *, const char *));
static char *_conv P((int, const char *, char *, const char *));
! static char *_fmt P((const char *, const struct tm *, char *, const char *));
size_t strftime P((char *, size_t, const char *, const struct tm *));
--- 34,98 ----
#endif /* !defined LIBC_SCCS */
#include "tzfile.h"
+ #include "fcntl.h"
! struct lc_time {
! const char *mon[12];
! const char *month[12];
! const char *wday[7];
! const char *weekday[7];
! const char *X_fmt;
! const char *x_fmt;
! const char *c_fmt;
! const char *am;
! const char *pm;
! const char *date_fmt;
};
!
! static const struct lc_time C_time_locale = {
! {
! "Jan", "Feb", "Mar", "Apr", "May", "Jun",
! "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
! }, {
! "January", "February", "March", "April", "May", "June",
! "July", "August", "September", "October", "November", "December"
! }, {
! "Sun", "Mon", "Tue", "Wed",
! "Thu", "Fri", "Sat"
! }, {
! "Sunday", "Monday", "Tuesday", "Wednesday",
! "Thursday", "Friday", "Saturday"
! },
!
! /* X_fmt */
! "%H:%M:%S",
!
! /*
! ** x_fmt
! ** Since the C language standard calls for
! ** "date, using locale's date format," anything goes.
! ** Using just numbers (as here) makes Quakers happier;
! ** it's also compatible with SVR4.
! */
! "%m/%d/%y",
!
! /* c_fmt */
! "%a %b %d %H:%M:%S %Y",
!
! "AM", "PM",
!
! /* date_fmt */
! "%a %b %e %H:%M:%S %Z %Y"
};
+ #if HAVE_SETLOCALE
+ # include <locale.h>
+ #endif
+
static char *_add P((const char *, char *, const char *));
static char *_conv P((int, const char *, char *, const char *));
! static char *_fmt P((const char *, const struct tm *, char *, const char *, struct lc_time *));
! static const struct lc_time *_loc P((struct lc_time *));
size_t strftime P((char *, size_t, const char *, const struct tm *));
***************
*** 68,75 ****
const struct tm *t;
{
char *p;
! p = _fmt(format, t, s, s + maxsize);
if (p == s + maxsize)
return 0;
*p = '\0';
--- 106,117 ----
const struct tm *t;
{
char *p;
+ struct lc_time localebuf;
! if (!format)
! format = "%c";
! localebuf.mon[0] = 0;
! p = _fmt(format, t, s, s + maxsize, &localebuf);
if (p == s + maxsize)
return 0;
*p = '\0';
***************
*** 77,87 ****
}
static char *
! _fmt(format, t, pt, ptlim)
const char *format;
const struct tm *t;
char *pt;
const char *ptlim;
{
for (; *format; ++format) {
if (*format == '%') {
--- 119,130 ----
}
static char *
! _fmt(format, t, pt, ptlim, locale)
const char *format;
const struct tm *t;
char *pt;
const char *ptlim;
+ struct lc_time *locale;
{
for (; *format; ++format) {
if (*format == '%') {
***************
*** 90,114 ****
case '\0':
--format;
break;
case 'A':
pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?
! "?" : Afmt[t->tm_wday], pt, ptlim);
continue;
case 'a':
pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?
! "?" : afmt[t->tm_wday], pt, ptlim);
continue;
case 'B':
pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?
! "?" : Bfmt[t->tm_mon], pt, ptlim);
continue;
case 'b':
case 'h':
pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?
! "?" : bfmt[t->tm_mon], pt, ptlim);
continue;
case 'c':
! pt = _fmt("%D %X", t, pt, ptlim);
continue;
case 'C':
/*
--- 133,166 ----
case '\0':
--format;
break;
+ case '+':
+ pt = _fmt(_loc(locale)->date_fmt, t,
+ pt, ptlim, locale);
+ continue;
case 'A':
pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?
! "?" : _loc(locale)->weekday[t->tm_wday],
! pt, ptlim);
continue;
case 'a':
pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?
! "?" : _loc(locale)->wday[t->tm_wday],
! pt, ptlim);
continue;
case 'B':
pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?
! "?" : _loc(locale)->month[t->tm_mon],
! pt, ptlim);
continue;
case 'b':
case 'h':
pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?
! "?" : _loc(locale)->mon[t->tm_mon],
! pt, ptlim);
continue;
case 'c':
! pt = _fmt(_loc(locale)->c_fmt, t,
! pt, ptlim, locale);
continue;
case 'C':
/*
***************
*** 122,148 ****
"%02d", pt, ptlim);
continue;
case 'D':
! pt = _fmt("%m/%d/%y", t, pt, ptlim);
! continue;
! case 'x':
! /*
! ** Version 3.0 of strftime from Arnold Robbins
! ** (arnold(a)skeeve.atl.ga.us) does the
! ** equivalent of...
! ** _fmt("%a %b %e %Y");
! ** ...for %x; since the X3J11 C language
! ** standard calls for "date, using locale's
! ** date format," anything goes. Using just
! ** numbers (as here) makes Quakers happier.
! ** Word from Paul Eggert (eggert(a)twinsun.com)
! ** is that %Y-%m-%d is the ISO standard date
! ** format, specified in ISO 2014 and later
! ** ISO 8601:1988, with a summary available in
! ** pub/doc/ISO/english/ISO8601.ps.Z on
! ** ftp.uni-erlangen.de.
! ** (ado, 5/30/93)
! */
! pt = _fmt("%m/%d/%y", t, pt, ptlim);
continue;
case 'd':
pt = _conv(t->tm_mday, "%02d", pt, ptlim);
--- 174,180 ----
"%02d", pt, ptlim);
continue;
case 'D':
! pt = _fmt("%m/%d/%y", t, pt, ptlim, locale);
continue;
case 'd':
pt = _conv(t->tm_mday, "%02d", pt, ptlim);
***************
*** 224,240 ****
pt, ptlim);
continue;
case 'R':
! pt = _fmt("%H:%M", t, pt, ptlim);
continue;
case 'r':
! pt = _fmt("%I:%M:%S %p", t, pt, ptlim);
continue;
case 'S':
pt = _conv(t->tm_sec, "%02d", pt, ptlim);
continue;
case 'T':
! case 'X':
! pt = _fmt("%H:%M:%S", t, pt, ptlim);
continue;
case 't':
pt = _add("\t", pt, ptlim);
--- 256,271 ----
pt, ptlim);
continue;
case 'R':
! pt = _fmt("%H:%M", t, pt, ptlim, locale);
continue;
case 'r':
! pt = _fmt("%I:%M:%S %p", t, pt, ptlim, locale);
continue;
case 'S':
pt = _conv(t->tm_sec, "%02d", pt, ptlim);
continue;
case 'T':
! pt = _fmt("%H:%M:%S", t, pt, ptlim, locale);
continue;
case 't':
pt = _add("\t", pt, ptlim);
***************
*** 321,327 ****
** "date as dd-bbb-YYYY"
** (ado, 5/24/93)
*/
! pt = _fmt("%e-%b-%Y", t, pt, ptlim);
continue;
case 'W':
pt = _conv((t->tm_yday + 7 -
--- 352,358 ----
** "date as dd-bbb-YYYY"
** (ado, 5/24/93)
*/
! pt = _fmt("%e-%b-%Y", t, pt, ptlim, locale);
continue;
case 'W':
pt = _conv((t->tm_yday + 7 -
***************
*** 332,337 ****
--- 363,376 ----
case 'w':
pt = _conv(t->tm_wday, "%d", pt, ptlim);
continue;
+ case 'X':
+ pt = _fmt(_loc(locale)->X_fmt, t,
+ pt, ptlim, locale);
+ continue;
+ case 'x':
+ pt = _fmt(_loc(locale)->x_fmt, t,
+ pt, ptlim, locale);
+ continue;
case 'y':
pt = _conv((t->tm_year + TM_YEAR_BASE) % 100,
"%02d", pt, ptlim);
***************
*** 390,393 ****
--- 429,526 ----
while (pt < ptlim && (*pt = *str++) != '\0')
++pt;
return pt;
+ }
+
+ static const struct lc_time *
+ _loc(locale)
+ struct lc_time *locale;
+ {
+ static const char locale_home[] = LOCALE_HOME;
+ static const char lc_time[] = "LC_TIME";
+ static char *locale_buf;
+ static char locale_buf_C[] = "C";
+
+ int fd;
+ char *lbuf, *name, *p;
+ const char **ap, *plim;
+ char filename[FILENAME_MAX];
+ struct stat st;
+ size_t namesize, bufsize;
+
+ /* Use locale->mon[0] to signal whether locale is already set up. */
+ if (locale->mon[0])
+ return locale;
+
+ #if HAVE_SETLOCALE
+ name = setlocale(LC_TIME, (char *)0);
+ #else
+ if (!(name = getenv("LC_ALL")) || !*name)
+ if (!(name = getenv(lc_time)) || !*name)
+ name = getenv("LANG");
+ #endif
+ if (!name || !*name)
+ goto no_locale;
+
+ /* If the locale name is the same as our cache, use the cache. */
+ lbuf = locale_buf;
+ if (lbuf && strcmp(name, lbuf) == 0) {
+ p = lbuf;
+ for (ap=(const char **)locale; ap<(const char **)(locale + 1); ap++)
+ *ap = p += strlen(p) + 1;
+ return locale;
+ }
+
+ /* Slurp the locale file into the cache. */
+ namesize = strlen(name) + 1;
+ if (sizeof(filename) < sizeof(locale_home) + namesize + sizeof(lc_time))
+ goto no_locale;
+ sprintf(filename, "%s/%s/%s", locale_home, name, lc_time);
+ fd = open(filename, O_RDONLY, 0);
+ if (fd < 0)
+ goto no_locale;
+ if (fstat(fd, &st) != 0)
+ goto bad_locale;
+ if (st.st_size <= 0)
+ goto bad_locale;
+ bufsize = namesize + st.st_size;
+ locale_buf = 0;
+ lbuf =
+ !lbuf || lbuf==locale_buf_C
+ ? malloc(bufsize)
+ : realloc(lbuf, bufsize);
+ if (!lbuf)
+ goto bad_locale;
+ strcpy(lbuf, name);
+ p = lbuf + namesize;
+ plim = p + st.st_size;
+ if (read(fd, p, (size_t)st.st_size) != st.st_size)
+ goto bad_lbuf;
+ if (close(fd) != 0)
+ goto bad_lbuf;
+
+ /* Parse the locale file into *locale. */
+ if (plim[-1] != '\n')
+ goto bad_lbuf;
+ for (ap=(const char **)locale; ap<(const char **)(locale + 1); ap++) {
+ if (p == plim)
+ goto bad_lbuf;
+ *ap = p;
+ while (*p != '\n')
+ p++;
+ *p++ = 0;
+ }
+
+ /* Record the successful parse in the cache. */
+ locale_buf = lbuf;
+
+ return locale;
+
+ bad_lbuf:
+ free(lbuf);
+ bad_locale:
+ (void) close(fd);
+ no_locale:
+ *locale = C_time_locale;
+ locale_buf = locale_buf_C;
+ return locale;
}
1
0
> From peggyd(a)sco.COM Fri May 6 14:03:24 1994
> Return-Path: <peggyd(a)sco.COM>
> Received: from relay1.UU.NET by elsie.nci.nih.gov (4.1/SMI-4.1)
> id AA01798; Fri, 6 May 94 14:03:23 EDT
> Received: from sco.sco.COM by relay1.UU.NET with SMTP
> (5.61/UUNET-internet-primary) id AAwotc03064; Fri, 6 May 94 14:03:19 -0400
> Received: from tehama.sco.COM by sco.sco.COM
> id aa08718; Wed, 6 May 70 11:08:32 PDT
> Received: from ping.sco.COM by tehama.sco.com id aa00201; 6 May 94 11:00 PDT
> From: mommy <peggyd(a)sco.COM>
> X-Mailer: SCO System V Mail (version 3.2)
> To: ado(a)elsie.nci.nih.gov
> Subject: timezones compatible with POSIX?
> Cc: peggyd(a)sco.COM
> Date: Fri, 6 May 94 10:59:55 PDT
> Message-Id: <9405061059.aa21366(a)ping.sco.com>
> Status: RO
>
>
> Hello,
>
> I work at the Santa Cruz Operation, a company that makes
> UNIX. I am designing and implementing the part of our
> installation that sets time zones. A search for complete,
> thorough timezone information led me to your anonymous ftp
> site, and I would like to use the information that you make
> available, if possible.
>
> However I am having some trouble reconciling the Rule
> format with the format we use, which is also the POSIX standard
> for timezone strings (as far as I can tell, looking at my
> POSIX doc). The problem is in the area of shifting to and from
> Daylight Savings Time. Our format is to use a Julian day,
> a month/week/day, or a week/day format. It's different enough from
> your Rule format that timezones defined in your format (such as Sun >= 11)
> do not work in our format for more than a few years at best (is
> that the 2nd week of the month? The 3rd week? It shifts.)
>
> I am wondering if anyone else has had this problem, and if you
> have seen any solutions? Are there alternate ways of expressing
> timezones? If you'd like more information I'd be happy to supply
> it.
>
> Thanks very much for your help,
>
> --peggyd(a)sco.com
4
3
The file tzcode94f.tar.gz was missing "optind.c" and a reference to it in the
Makefile; tzcode94g.tar.gz remedies the problem.
--ado
1
0
The file tzcode94f.tar.gz is now available for anonymous ftp from the
"~ftp/pub" directory on elsie.nci.nih.gov (128.231.16.1). It includes
changes to avoid overflow in difftime, as well as changes to cope with
the 52/53 challenge in strftime.
--ado
1
0
Let's take the common case where time_t ranges from -2147483648
through 2147483647, and `double' is IEEE 754 double precision.
Then, under tz-1994e, the program
#include <time.h>
#include <stdio.h>
#define MAX_TIME 2147483647
#define MIN_TIME (-1 - MAX_TIME)
int main() {
printf("difftime(%ld, %ld) = %.17g\n",
(long) MAX_TIME, (long) MIN_TIME, difftime(MAX_TIME, MIN_TIME));
return 0;
}
outputs
difftime(2147483647, -2147483648) = -1
There's no reason for difftime to report the wrong answer, since the
result is exactly representable. Here is a patch.
===================================================================
RCS file: difftime.c,v
retrieving revision 1994.5
retrieving revision 1994.5.1.1
diff -c -r1994.5 -r1994.5.1.1
*** difftime.c 1992/04/23 17:34:30 1994.5
--- difftime.c 1994/05/03 04:30:43 1994.5.1.1
***************
*** 13,17 ****
const time_t time1;
const time_t time0;
{
! return time1 - time0;
}
--- 13,28 ----
const time_t time1;
const time_t time0;
{
! if (sizeof(time_t) < sizeof(double))
! return (double) time1 - (double) time0;
! else {
! time_t delta = time1 - time0;
! if ((~time1 & time0 & delta) < 0) {
! time_t hibit;
! for (hibit = 1; (hibit <<= 1) > 0; )
! ;
! return delta - 2.0 * hibit;
! } else
! return delta;
! }
}
1
0