Core: Improved timezone support, ScanWwwTime

git-svn-id: svn://ultimatepp.org/upp/trunk@7096 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2014-03-25 11:21:13 +00:00
parent 6d28bd0678
commit 2a06d539c7
6 changed files with 119 additions and 8 deletions

View file

@ -1,4 +1,6 @@
String WwwFormat(Time tm);
bool ScanWwwTime(const char *s, Time& tm);
Time ScanWwwTime(const char *s);
String MIMECharsetName(byte charset);

View file

@ -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)

View file

@ -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)

View file

@ -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);

View file

@ -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].&]

View file

@ -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