From 2a06d539c7665f09169ab12fa6aa9b8c42f2e4a6 Mon Sep 17 00:00:00 2001 From: cxl Date: Tue, 25 Mar 2014 11:21:13 +0000 Subject: [PATCH] Core: Improved timezone support, ScanWwwTime git-svn-id: svn://ultimatepp.org/upp/trunk@7096 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/Core/Inet.h | 2 + uppsrc/Core/InetUtil.cpp | 53 +++++++++++++++++++++++++- uppsrc/Core/TimeDate.cpp | 37 ++++++++++++++++-- uppsrc/Core/TimeDate.h | 3 ++ uppsrc/Core/src.tpp/DateTime$en-us.tpp | 17 +++++++++ uppsrc/Core/src.tpp/Inet$en-us.tpp | 15 +++++++- 6 files changed, 119 insertions(+), 8 deletions(-) diff --git a/uppsrc/Core/Inet.h b/uppsrc/Core/Inet.h index ae145e29a..069579861 100644 --- a/uppsrc/Core/Inet.h +++ b/uppsrc/Core/Inet.h @@ -1,4 +1,6 @@ String WwwFormat(Time tm); +bool ScanWwwTime(const char *s, Time& tm); +Time ScanWwwTime(const char *s); String MIMECharsetName(byte charset); diff --git a/uppsrc/Core/InetUtil.cpp b/uppsrc/Core/InetUtil.cpp index 64cdd1597..4fa097e44 100644 --- a/uppsrc/Core/InetUtil.cpp +++ b/uppsrc/Core/InetUtil.cpp @@ -2,6 +2,10 @@ NAMESPACE_UPP +static const char *s_www_month[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + String WwwFormat(Time tm) { static const char *dayofweek[] = @@ -10,9 +14,54 @@ String WwwFormat(Time tm) { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; return String().Cat() << dayofweek[DayOfWeek(tm)] << ", " - << (int)tm.day << ' ' << month[tm.month - 1] + << (int)tm.day << ' ' << s_www_month[tm.month - 1] << ' ' << (int)tm.year - << ' ' << Sprintf("%2d:%02d:%02d +0100", tm.hour, tm.minute, tm.second); + << ' ' << Sprintf("%2d:%02d:%02d " + GetTimeZoneText(), tm.hour, tm.minute, tm.second); +} + +int FindMonth(const String& m) +{ + for(int i = 0; i < 12; i++) + if(s_www_month[i] == m) + return i; + return -1; +} + +bool ScanWwwTime(const char *s, Time& tm) +{ + CParser p(s); + try { + if(p.IsId()) { // Skip day of week + p.SkipTerm(); + p.Char(','); + } + tm.day = p.ReadInt(1, 31); + int n = FindMonth(p.ReadId()) + 1; + if(n < 1 || n > 12) + return false; + tm.month = n; + tm.year = p.ReadInt(1, 4000); + if(tm.year < 100) + tm.year += 2000; + tm.hour = p.ReadInt(0, 23); + p.PassChar(':'); + tm.minute = p.ReadInt(0, 59); + if(p.Char(':')) + tm.second = p.ReadInt(0, 59); + tm += 60 * (ScanTimeZone(p.GetPtr()) - GetTimeZone()); + } + catch(CParser::Error) { + return false; + } + return tm.IsValid(); +} + +Time ScanWwwTime(const char *s) +{ + Time tm; + if(ScanWwwTime(s, tm)) + return tm; + return Null; } String MIMECharsetName(byte charset) diff --git a/uppsrc/Core/TimeDate.cpp b/uppsrc/Core/TimeDate.cpp index a2f298d20..3d3392a57 100644 --- a/uppsrc/Core/TimeDate.cpp +++ b/uppsrc/Core/TimeDate.cpp @@ -611,12 +611,41 @@ bool SetSysTime(Time time) #endif } +int GetTimeZone() +{ + static int zone; + ONCELOCK { + for(;;) { // This is somewhat ugly, but unified approach to get time zone offset + Time t0 = GetSysTime(); + Time gmtime = GetUtcTime(); + Time ltime = GetSysTime(); + if(GetSysTime() - t0 < 1) { // Make sure that there is not much time between calls + zone = (int)(ltime - gmtime) / 60; // Round to minutes + break; + } + } + } + return zone; +} + +String FormatTimeZone(int n) +{ + return (n < 0 ? "-" : "+") + Format("%02.2d%02.2d", abs(n) / 60, abs(n) % 60); +} + String GetTimeZoneText() { - Time gmtime = GetUtcTime(); - Time ltime = GetSysTime(); - int d = (int)(ltime - gmtime) / 600; - return Format("+%02.2d%01.1d0", d / 6, d % 6); + return FormatTimeZone(GetTimeZone()); +} + +int ScanTimeZone(const char *s) +{ + int n = atoi(s); + int hour = abs(n) / 100; + int minutes = abs(n) % 100; + if(hour >= 0 && hour <= 12 && minutes >= 0 && minutes < 60) + return sgn(n) * (hour * 60 + minutes); + return 0; } int GetLeapSeconds(Date dt) diff --git a/uppsrc/Core/TimeDate.h b/uppsrc/Core/TimeDate.h index 573bd15c8..eaa133efb 100644 --- a/uppsrc/Core/TimeDate.h +++ b/uppsrc/Core/TimeDate.h @@ -155,7 +155,10 @@ inline String AsString(const Time& time) { return Format(time); } bool SetSysTime(Time time); // only root/sysadmin can do this... +int GetTimeZone(); String GetTimeZoneText(); +int ScanTimeZoneText(const char *s); +int ScanTimeZone(const char *s); int GetLeapSeconds(Date dt); int64 GetUTCSeconds(Time tm); diff --git a/uppsrc/Core/src.tpp/DateTime$en-us.tpp b/uppsrc/Core/src.tpp/DateTime$en-us.tpp index e46042836..3a0529450 100644 --- a/uppsrc/Core/src.tpp/DateTime$en-us.tpp +++ b/uppsrc/Core/src.tpp/DateTime$en-us.tpp @@ -234,6 +234,23 @@ of leap years.&] [s2;%% Returns the Easter day for given [%-*@3 year].&] [s3;%% &] [s4; &] +[s5;:GetTimeZone`(`): [@(0.0.255) int]_[* GetTimeZone]()&] +[s2;%% Returns a local timezone as offset from GMT in minutes.&] +[s3; &] +[s4; &] +[s5;:FormatTimeZone`(int`): [_^String^ String]_[* FormatTimeZone]([@(0.0.255) int]_[*@3 n])&] +[s2;%% Formats timezone in common format, used e.g. in internet dates.&] +[s3;%% &] +[s4; &] +[s5;:GetTimeZoneText`(`): [_^String^ String]_[* GetTimeZoneText]()&] +[s2;%% Same as FormatTimeZone(GetTimeZone()).&] +[s3; &] +[s4; &] +[s5;:ScanTimeZone`(const char`*`): [@(0.0.255) int]_[* ScanTimeZone]([@(0.0.255) const]_[@(0.0.255) c +har]_`*[*@3 s])&] +[s2;%% Scans timezone text to obtain offset in seconds.&] +[s3;%% &] +[s4; &] [s5;:GetLeapSeconds`(Date`): [@(0.0.255) int]_[* GetLeapSeconds]([_^Date^ Date]_[*@3 dt])&] [s2;%% Returns the number of leap seconds that has occured since the start of adding leap seconds till [%-*@3 dt].&] diff --git a/uppsrc/Core/src.tpp/Inet$en-us.tpp b/uppsrc/Core/src.tpp/Inet$en-us.tpp index 8b0cbaf91..57c624751 100644 --- a/uppsrc/Core/src.tpp/Inet$en-us.tpp +++ b/uppsrc/Core/src.tpp/Inet$en-us.tpp @@ -13,8 +13,19 @@ topic "Internet utility"; [ {{10000@(113.42.0) [s0;%% [*@7;4 Internet format utility functions]]}}&] [s3; &] [s5;:WwwFormat`(Time`): [_^String^ String]_[* WwwFormat]([_^Time^ Time]_[*@3 tm])&] -[s2;%% Returns Time in format commonly used in HTTP and other internet -protocol, like `"Sun, 15 Apr 2012 16:00:25 GMT`".&] +[s2;%% Returns Time in format defined by RFC2822, commonly used in +HTTP and other internet protocol, like `"Sun, 15 Apr 2012 16:00:25 +GMT`".&] +[s3;%% &] +[s4; &] +[s5;:ScanWwwTime`(const char`*`,Time`&`): [@(0.0.255) bool]_[* ScanWwwTime]([@(0.0.255) con +st]_[@(0.0.255) char]_`*[*@3 s], [_^Time^ Time][@(0.0.255) `&]_[*@3 tm])&] +[s2;%% Scans Time format as defined by RFC2822, returns true on success..&] +[s3;%% &] +[s4; &] +[s5;:ScanWwwTime`(const char`*`): [_^Time^ Time]_[* ScanWwwTime]([@(0.0.255) const]_[@(0.0.255) c +har]_`*[*@3 s])&] +[s2;%% Scans Time format as defined by RFC2822, returns Null on failure.&] [s3;%% &] [s4; &] [s5;:MIMECharsetName`(byte`): [_^String^ String]_[* MIMECharsetName]([_^byte^ byte]_[*@3 char