allow to use a first|last weekday name when defining a timezone dst
the format of a 'start' or 'end' field in a dst is: MM-[first|last]:[monday|tuesday|wednesday|thursday|friday|saturday|sunday] HH:MM:SS or just as beforehand: MM-DD HH:MM:SS a sample timezone: { name = "tz_+01:00d" id = "40" offset_str = "+01:00" dst = ( { year = "2001" has_dst = true offset_str = "+01:00" start = "03-last-sunday 01:00" end = "10-last-sunday 01:00" } ) # end of dst }
This commit is contained in:
parent
0724ca8eb3
commit
0cebb2dc52
|
@ -57,40 +57,9 @@ void TimeZone::Dst::Clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool TimeZone::Dst::IsDstUsed(const pt::Date & date) const
|
bool TimeZone::Dst::IsDstUsed(const pt::Date & utc_date) const
|
||||||
{
|
{
|
||||||
if( !has_dst )
|
return has_dst && start.Compare(utc_date, true) <= 0 && utc_date.Compare(end) < 0;
|
||||||
return false;
|
|
||||||
|
|
||||||
if( Compare(start, date) <= 0 ) // !! CHECK ME <= or < ? (what about the one second?)
|
|
||||||
if( Compare(date, end) < 0 )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int TimeZone::Dst::Compare(const pt::Date & date1, const pt::Date & date2) const
|
|
||||||
{
|
|
||||||
// year is ignored
|
|
||||||
|
|
||||||
if( date1.month != date2.month )
|
|
||||||
return date1.month - date2.month;
|
|
||||||
|
|
||||||
if( date1.day != date2.day )
|
|
||||||
return date1.day - date2.day;
|
|
||||||
|
|
||||||
if( date1.hour != date2.hour )
|
|
||||||
return date1.hour - date2.hour;
|
|
||||||
|
|
||||||
if( date1.min != date2.min )
|
|
||||||
return date1.min - date2.min;
|
|
||||||
|
|
||||||
if( date1.sec != date2.sec )
|
|
||||||
return date1.sec - date2.sec;
|
|
||||||
|
|
||||||
// dates are equal
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -290,9 +259,135 @@ time_t TimeZone::GetOffset(pt::Space & space)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const wchar_t * TimeZone::SkipDstDateSeparator(const wchar_t * date_str)
|
||||||
|
{
|
||||||
|
date_str = pt::skip_white(date_str, false, false);
|
||||||
|
|
||||||
|
// the same separators as in the pikotools library
|
||||||
|
if( *date_str == '-' || *date_str == '/' || *date_str == '.' )
|
||||||
|
{
|
||||||
|
++date_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pt::skip_white(date_str, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int TimeZone::ParseDstDateWeekday(const wchar_t * date_str, const wchar_t ** after_date_str)
|
||||||
|
{
|
||||||
|
date_str = SkipDstDateSeparator(date_str);
|
||||||
|
int weekday_int = -1;
|
||||||
|
|
||||||
|
struct WeekDay {
|
||||||
|
const wchar_t * name;
|
||||||
|
int weekday;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const WeekDay week_days[] = {
|
||||||
|
{L"sunday", 0},
|
||||||
|
{L"monday", 1},
|
||||||
|
{L"tuesday", 2},
|
||||||
|
{L"wednesday", 3},
|
||||||
|
{L"thursday", 4},
|
||||||
|
{L"friday", 5},
|
||||||
|
{L"saturday", 6},
|
||||||
|
};
|
||||||
|
|
||||||
|
for(const WeekDay & week_day : week_days)
|
||||||
|
{
|
||||||
|
if( pt::is_substr(week_day.name, date_str) )
|
||||||
|
{
|
||||||
|
date_str += wcslen(week_day.name);
|
||||||
|
weekday_int = week_day.weekday;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*after_date_str = date_str;
|
||||||
|
return weekday_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TimeZone::ParseDstDateDay(bool is_first, int weekday, pt::Date & date)
|
||||||
|
{
|
||||||
|
int len = 1;
|
||||||
|
int adder = 1;
|
||||||
|
|
||||||
|
if( is_first )
|
||||||
|
{
|
||||||
|
len = pt::Date::MonthLen(date.year, date.month);
|
||||||
|
date.day = 1;
|
||||||
|
adder = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
len = pt::Date::MonthLen(date.year, date.month);
|
||||||
|
date.day = len;
|
||||||
|
adder = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0 ; i < len && date.WeekDay() != weekday ; ++i)
|
||||||
|
{
|
||||||
|
date.day += adder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool TimeZone::ParseDstDate(int year, const wchar_t * date_str, pt::Date & date)
|
||||||
|
{
|
||||||
|
bool was_overflow = false;
|
||||||
|
bool is_ok = false;
|
||||||
|
const wchar_t * after_date_str;
|
||||||
|
|
||||||
|
date.Clear();
|
||||||
|
date.year = year;
|
||||||
|
|
||||||
|
date_str = pt::skip_white(date_str, false, false);
|
||||||
|
date.month = pt::to_i(date_str, 10, &after_date_str, &was_overflow, true);
|
||||||
|
|
||||||
|
if( !was_overflow && after_date_str != date_str )
|
||||||
|
{
|
||||||
|
date_str = SkipDstDateSeparator(after_date_str);
|
||||||
|
|
||||||
|
if( pt::is_substr(L"first", date_str) )
|
||||||
|
{
|
||||||
|
date_str += 5; // length of "first"
|
||||||
|
int weekday = ParseDstDateWeekday(date_str, &date_str);
|
||||||
|
|
||||||
|
if( weekday >= 0 )
|
||||||
|
{
|
||||||
|
ParseDstDateDay(true, weekday, date);
|
||||||
|
is_ok = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if( pt::is_substr(L"last", date_str) )
|
||||||
|
{
|
||||||
|
date_str += 4; // length of "last"
|
||||||
|
int weekday = ParseDstDateWeekday(date_str, &date_str);
|
||||||
|
|
||||||
|
if( weekday >= 0 )
|
||||||
|
{
|
||||||
|
ParseDstDateDay(false, weekday, date);
|
||||||
|
is_ok = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
date.day = pt::to_i(date_str, 10, &after_date_str, &was_overflow, true);
|
||||||
|
is_ok = !was_overflow && after_date_str != date_str;
|
||||||
|
date_str = after_date_str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_ok && date.ParseTime(date_str) && date.IsCorrectDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool TimeZone::SetTzDst(pt::Space & year)
|
bool TimeZone::SetTzDst(pt::Space & year)
|
||||||
{
|
{
|
||||||
time_t h24 = 60 * 60 * 24; // 24 hours
|
time_t h24 = pt::Date::ONE_DAY;
|
||||||
bool result = true;
|
bool result = true;
|
||||||
Dst dst;
|
Dst dst;
|
||||||
|
|
||||||
|
@ -305,19 +400,15 @@ bool TimeZone::SetTzDst(pt::Space & year)
|
||||||
if( year_int < 1970 || year_int > 10000 )
|
if( year_int < 1970 || year_int > 10000 )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
dst.has_dst = year.to_bool(L"has_dst", false);
|
bool has_dst = year.to_bool(L"has_dst", false);
|
||||||
|
std::wstring * dst_start = year.get_wstr(L"start");
|
||||||
|
std::wstring * dst_end = year.get_wstr(L"end");
|
||||||
|
|
||||||
if( dst.has_dst )
|
if( has_dst && dst_start && dst_end )
|
||||||
{
|
{
|
||||||
dst.start.year = year_int;
|
dst.has_dst = true;
|
||||||
dst.end.year = year_int;
|
result = result && ParseDstDate(year_int, dst_start->c_str(), dst.start);
|
||||||
|
result = result && ParseDstDate(year_int, dst_end->c_str(), dst.end);
|
||||||
if( !dst.start.ParseMonthDayTime(year.to_wstr(L"start")) )
|
|
||||||
result = false;
|
|
||||||
|
|
||||||
if( !dst.end.ParseMonthDayTime(year.to_wstr(L"end")) )
|
|
||||||
result = false;
|
|
||||||
|
|
||||||
dst.offset = GetOffset(year);
|
dst.offset = GetOffset(year);
|
||||||
|
|
||||||
if( dst.offset < -h24 || dst.offset > h24 )
|
if( dst.offset < -h24 || dst.offset > h24 )
|
||||||
|
@ -343,7 +434,7 @@ bool TimeZone::SetTz(pt::Space & space)
|
||||||
|
|
||||||
id = space.to_int(L"id", -1);
|
id = space.to_int(L"id", -1);
|
||||||
offset = GetOffset(space);
|
offset = GetOffset(space);
|
||||||
time_t h24 = 60 * 60 * 24; // 24 hours
|
time_t h24 = pt::Date::ONE_DAY;
|
||||||
|
|
||||||
if( offset < -h24 || offset > h24 )
|
if( offset < -h24 || offset > h24 )
|
||||||
result = false;
|
result = false;
|
||||||
|
|
|
@ -74,16 +74,7 @@ public:
|
||||||
// checking whether specified 'date' is in the range of <start, end>
|
// checking whether specified 'date' is in the range of <start, end>
|
||||||
// the year field in date, start and end is ignored
|
// the year field in date, start and end is ignored
|
||||||
// has_dst must be true
|
// has_dst must be true
|
||||||
bool IsDstUsed(const pt::Date & date) const;
|
bool IsDstUsed(const pt::Date & utc_date) const;
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
// Compare returns zero if date1 and date2 are equal
|
|
||||||
// return value less than zero if date1 is lower than date2
|
|
||||||
// and a value greater than zero if date1 is greater than date2
|
|
||||||
// the year field is ignored
|
|
||||||
int Compare(const pt::Date & date1, const pt::Date & date2) const;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -156,6 +147,10 @@ private:
|
||||||
|
|
||||||
time_t ParseStrOffset(const wchar_t * str);
|
time_t ParseStrOffset(const wchar_t * str);
|
||||||
time_t GetOffset(pt::Space & space);
|
time_t GetOffset(pt::Space & space);
|
||||||
|
int ParseDstDateWeekday(const wchar_t * date_str, const wchar_t ** after_date_str);
|
||||||
|
void ParseDstDateDay(bool is_first, int weekday, pt::Date & date);
|
||||||
|
const wchar_t * SkipDstDateSeparator(const wchar_t * date_str);
|
||||||
|
bool ParseDstDate(int year, const wchar_t * date_str, pt::Date & date);
|
||||||
bool SetTzDst(pt::Space & year);
|
bool SetTzDst(pt::Space & year);
|
||||||
static void PrintOffsetPart(long val, pt::Stream & str);
|
static void PrintOffsetPart(long val, pt::Stream & str);
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@ dst = (
|
||||||
year = "2012" # daylight saving time in a specified year
|
year = "2012" # daylight saving time in a specified year
|
||||||
has_dst = false # whether the time zone has daylight saving time {bool} in this year
|
has_dst = false # whether the time zone has daylight saving time {bool} in this year
|
||||||
offset_str = "00:00" # offset of the daylight saving time
|
offset_str = "00:00" # offset of the daylight saving time
|
||||||
start = "" # when the daylight saving time starts, format: MM:DD HH:MM:SS
|
start = "" # when the daylight saving time starts treated as utc date, format: MM-DD HH:MM:SS or MM-[first|last]:[monday|tuesday|wednesday|thursday|friday|saturday|sunday] HH:MM:SS
|
||||||
end = "" # when the daylight saving time ends, format: MM:DD HH:MM:SS
|
end = "" # when the daylight saving time ends treated as utc date, format the same as in the start
|
||||||
}
|
}
|
||||||
|
|
||||||
) # end of dst
|
) # end of dst
|
||||||
|
@ -711,11 +711,12 @@ offset_str = "00:00"
|
||||||
dst = (
|
dst = (
|
||||||
|
|
||||||
{
|
{
|
||||||
year = "2012"
|
year = "2001"
|
||||||
has_dst = true
|
has_dst = true
|
||||||
offset_str = "+01:00"
|
offset_str = "+01:00"
|
||||||
start = "03-25 01:00"
|
start = "03-last-sunday 01:00"
|
||||||
end = "10-28 01:00"}
|
end = "10-last-sunday 01:00"
|
||||||
|
}
|
||||||
|
|
||||||
) # end of dst
|
) # end of dst
|
||||||
}
|
}
|
||||||
|
@ -730,11 +731,12 @@ offset_str = "00:00"
|
||||||
dst = (
|
dst = (
|
||||||
|
|
||||||
{
|
{
|
||||||
year = "2012"
|
year = "1970"
|
||||||
has_dst = true
|
has_dst = false
|
||||||
offset_str = "+01:00"
|
offset_str = "00:00"
|
||||||
start = "03-25 01:00"
|
start = ""
|
||||||
end = "10-28 01:00"}
|
end = ""
|
||||||
|
}
|
||||||
|
|
||||||
) # end of dst
|
) # end of dst
|
||||||
}
|
}
|
||||||
|
@ -749,11 +751,12 @@ offset_str = "+01:00"
|
||||||
dst = (
|
dst = (
|
||||||
|
|
||||||
{
|
{
|
||||||
year = "2012"
|
year = "2001"
|
||||||
has_dst = true
|
has_dst = true
|
||||||
offset_str = "+01:00"
|
offset_str = "+01:00"
|
||||||
start = "03-25 01:00"
|
start = "03-last-sunday 01:00"
|
||||||
end = "10-28 01:00"}
|
end = "10-last-sunday 01:00"
|
||||||
|
}
|
||||||
|
|
||||||
) # end of dst
|
) # end of dst
|
||||||
}
|
}
|
||||||
|
@ -768,11 +771,12 @@ offset_str = "+01:00"
|
||||||
dst = (
|
dst = (
|
||||||
|
|
||||||
{
|
{
|
||||||
year = "2012"
|
year = "2001"
|
||||||
has_dst = true
|
has_dst = true
|
||||||
offset_str = "+01:00"
|
offset_str = "+01:00"
|
||||||
start = "03-25 01:00"
|
start = "03-last-sunday 01:00"
|
||||||
end = "10-28 01:00"}
|
end = "10-last-sunday 01:00"
|
||||||
|
}
|
||||||
|
|
||||||
) # end of dst
|
) # end of dst
|
||||||
}
|
}
|
||||||
|
@ -787,11 +791,12 @@ offset_str = "+01:00"
|
||||||
dst = (
|
dst = (
|
||||||
|
|
||||||
{
|
{
|
||||||
year = "2012"
|
year = "2001"
|
||||||
has_dst = true
|
has_dst = true
|
||||||
offset_str = "+01:00"
|
offset_str = "+01:00"
|
||||||
start = "03-25 01:00"
|
start = "03-last-sunday 01:00"
|
||||||
end = "10-28 01:00"}
|
end = "10-last-sunday 01:00"
|
||||||
|
}
|
||||||
|
|
||||||
) # end of dst
|
) # end of dst
|
||||||
}
|
}
|
||||||
|
@ -806,32 +811,12 @@ offset_str = "+01:00"
|
||||||
dst = (
|
dst = (
|
||||||
|
|
||||||
{
|
{
|
||||||
year = "2012"
|
year = "2001"
|
||||||
has_dst = true
|
has_dst = true
|
||||||
offset_str = "+01:00"
|
offset_str = "+01:00"
|
||||||
start = "03-25 01:00"
|
start = "03-last-sunday 01:00"
|
||||||
end = "10-28 01:00"}
|
end = "10-last-sunday 01:00"
|
||||||
|
}
|
||||||
{
|
|
||||||
year = "2018"
|
|
||||||
has_dst = true
|
|
||||||
offset_str = "+01:00"
|
|
||||||
start = "03-25 01:00"
|
|
||||||
end = "10-28 01:00"}
|
|
||||||
|
|
||||||
{
|
|
||||||
year = "2022"
|
|
||||||
has_dst = true
|
|
||||||
offset_str = "+01:00"
|
|
||||||
start = "03-27 01:00"
|
|
||||||
end = "10-30 01:00"}
|
|
||||||
|
|
||||||
{
|
|
||||||
year = "2023"
|
|
||||||
has_dst = true
|
|
||||||
offset_str = "+01:00"
|
|
||||||
start = "03-26 01:00"
|
|
||||||
end = "10-29 01:00"}
|
|
||||||
|
|
||||||
) # end of dst
|
) # end of dst
|
||||||
|
|
||||||
|
@ -908,11 +893,11 @@ offset_str = "+02:00"
|
||||||
dst = (
|
dst = (
|
||||||
|
|
||||||
{
|
{
|
||||||
year = "2012"
|
year = "2001"
|
||||||
has_dst = false
|
has_dst = true
|
||||||
offset_str = "00:00"
|
offset_str = "+01:00"
|
||||||
start = ""
|
start = "03-last-sunday 01:00"
|
||||||
end = ""
|
end = "10-last-sunday 01:00"
|
||||||
}
|
}
|
||||||
|
|
||||||
) # end of dst
|
) # end of dst
|
||||||
|
@ -1008,11 +993,11 @@ offset_str = "+02:00"
|
||||||
dst = (
|
dst = (
|
||||||
|
|
||||||
{
|
{
|
||||||
year = "2012"
|
year = "2001"
|
||||||
has_dst = false
|
has_dst = true
|
||||||
offset_str = "00:00"
|
offset_str = "+01:00"
|
||||||
start = ""
|
start = "03-last-sunday 01:00"
|
||||||
end = ""
|
end = "10-last-sunday 01:00"
|
||||||
}
|
}
|
||||||
|
|
||||||
) # end of dst
|
) # end of dst
|
||||||
|
@ -1068,11 +1053,11 @@ offset_str = "+02:00"
|
||||||
dst = (
|
dst = (
|
||||||
|
|
||||||
{
|
{
|
||||||
year = "2012"
|
year = "2001"
|
||||||
has_dst = false
|
has_dst = true
|
||||||
offset_str = "00:00"
|
offset_str = "+01:00"
|
||||||
start = ""
|
start = "03-last-sunday 01:00"
|
||||||
end = ""
|
end = "10-last-sunday 01:00"
|
||||||
}
|
}
|
||||||
|
|
||||||
) # end of dst
|
) # end of dst
|
||||||
|
|
|
@ -643,7 +643,7 @@ tz_+02:00c = Bejrut
|
||||||
tz_+02:00d = Kair
|
tz_+02:00d = Kair
|
||||||
tz_+02:00e = Damaszek
|
tz_+02:00e = Damaszek
|
||||||
tz_+02:00f = Harare, Pretoria
|
tz_+02:00f = Harare, Pretoria
|
||||||
tz_+02:00g = Helsinki, Kijów, Ryga, Sofia, Talin, Wilno
|
tz_+02:00g = Helsinki, Kijów, Ryga, Sofia, Tallin, Wilno
|
||||||
tz_+02:00h = Stambuł
|
tz_+02:00h = Stambuł
|
||||||
tz_+02:00i = Jerozolima
|
tz_+02:00i = Jerozolima
|
||||||
tz_+02:00j = Nikozja
|
tz_+02:00j = Nikozja
|
||||||
|
|
Loading…
Reference in New Issue