@@ -70,8 +70,9 @@ module Crystal::System::Time
70
70
end
71
71
72
72
def self.load_localtime : ::Time ::Location ?
73
- if LibC .GetTimeZoneInformation (out info) != LibC ::TIME_ZONE_ID_INVALID
74
- initialize_location_from_TZI(info, " Local" )
73
+ if LibC .GetDynamicTimeZoneInformation (out info) != LibC ::TIME_ZONE_ID_INVALID
74
+ windows_name = String .from_utf16(info.timeZoneKeyName.to_slice, truncate_at_null: true )
75
+ initialize_location_from_TZI(pointerof (info).as(LibC ::TIME_ZONE_INFORMATION * ).value, " Local" , windows_name)
75
76
end
76
77
end
77
78
@@ -105,70 +106,38 @@ module Crystal::System::Time
105
106
)
106
107
WindowsRegistry .get_raw(sub_handle, Std , tzi.standardName.to_slice.to_unsafe_bytes)
107
108
WindowsRegistry .get_raw(sub_handle, Dlt , tzi.daylightName.to_slice.to_unsafe_bytes)
108
- initialize_location_from_TZI(tzi, iana_name)
109
+ initialize_location_from_TZI(tzi, iana_name, windows_name )
109
110
end
110
111
end
111
112
end
112
113
113
- private def self.initialize_location_from_TZI (info , name )
114
+ private def self.initialize_location_from_TZI (info , name , windows_name )
114
115
stdname, dstname = normalize_zone_names(info)
115
116
116
- if info.standardDate.wMonth == 0 _u16
117
+ if info.standardDate.wMonth == 0 _u16 || info.daylightDate.wMonth == 0 _ u16
117
118
# No DST
118
119
zone = ::Time ::Location ::Zone .new(stdname, info.bias * BIAS_TO_OFFSET_FACTOR , false )
119
- return ::Time ::Location .new(name, [zone])
120
+ default_tz_args = {0 , 0 , ::Time ::TZ ::MonthWeekDay .default, ::Time ::TZ ::MonthWeekDay .default}
121
+ return ::Time ::WindowsLocation .new(name, [zone], windows_name, default_tz_args)
120
122
end
121
123
122
124
zones = [
123
125
::Time ::Location ::Zone .new(stdname, (info.bias + info.standardBias) * BIAS_TO_OFFSET_FACTOR , false ),
124
126
::Time ::Location ::Zone .new(dstname, (info.bias + info.daylightBias) * BIAS_TO_OFFSET_FACTOR , true ),
125
127
]
126
128
127
- first_date = info.standardDate
128
- second_date = info.daylightDate
129
- first_index = 0 _u8
130
- second_index = 1 _u8
129
+ std_index = 0
130
+ dst_index = 1
131
+ transition1 = systemtime_to_mwd(info.daylightDate)
132
+ transition2 = systemtime_to_mwd(info.standardDate)
133
+ tz_args = {std_index, dst_index, transition1, transition2}
131
134
132
- if info.standardDate.wMonth > info.daylightDate.wMonth
133
- first_date, second_date = second_date, first_date
134
- first_index, second_index = second_index, first_index
135
- end
136
-
137
- transitions = [] of ::Time ::Location ::ZoneTransition
138
-
139
- current_year = ::Time .utc.year
140
-
141
- (current_year - 100 ).upto(current_year + 100 ) do |year |
142
- tstamp = calculate_switchdate_in_year(year, first_date) - (zones[second_index].offset)
143
- transitions << ::Time ::Location ::ZoneTransition .new(tstamp, first_index, first_index == 0 , false )
144
-
145
- tstamp = calculate_switchdate_in_year(year, second_date) - (zones[first_index].offset)
146
- transitions << ::Time ::Location ::ZoneTransition .new(tstamp, second_index, second_index == 0 , false )
147
- end
148
-
149
- ::Time ::Location .new(name, zones, transitions)
135
+ ::Time ::WindowsLocation .new(name, zones, windows_name, tz_args)
150
136
end
151
137
152
- # Calculates the day of a DST switch in year *year* by extrapolating the date given in
153
- # *systemtime* (for the current year).
154
- #
155
- # Returns the number of seconds since UNIX epoch (Jan 1 1970) in the local time zone.
156
- private def self.calculate_switchdate_in_year (year , systemtime )
157
- # Windows specifies daylight savings information in "day in month" format:
158
- # wMonth is month number (1-12)
159
- # wDayOfWeek is appropriate weekday (Sunday=0 to Saturday=6)
160
- # wDay is week within the month (1 to 5, where 5 is last week of the month)
161
- # wHour, wMinute and wSecond are absolute time
162
- ::Time .month_week_date(
163
- year,
164
- systemtime.wMonth.to_i32,
165
- systemtime.wDay.to_i32,
166
- systemtime.wDayOfWeek.to_i32,
167
- systemtime.wHour.to_i32,
168
- systemtime.wMinute.to_i32,
169
- systemtime.wSecond.to_i32,
170
- location: ::Time ::Location ::UTC ,
171
- ).to_unix
138
+ private def self.systemtime_to_mwd (time )
139
+ seconds = 3600 * time.wHour + 60 * time.wMinute + time.wSecond
140
+ ::Time ::TZ ::MonthWeekDay .new(time.wMonth.to_i8, time.wDay.to_i8, time.wDayOfWeek.to_i8, seconds)
172
141
end
173
142
174
143
# Normalizes the names of the standard and dst zones.
0 commit comments