From c2e63f92904286095d74b3d76a2cccaacecdbb26 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Thu, 31 Jan 2019 20:56:40 +0000 Subject: [PATCH] added: to Date: support for parsing timezone offsets git-svn-id: svn://ttmath.org/publicrep/pikotools/trunk@1168 e52654a7-88a9-db11-a3e9-0013d4bc506e --- date/date.cpp | 2 +- date/date.h | 84 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/date/date.cpp b/date/date.cpp index 75277a2..1e79c39 100644 --- a/date/date.cpp +++ b/date/date.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2012, Tomasz Sowa + * Copyright (c) 2012-2018, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/date/date.h b/date/date.h index b891413..f17b7ab 100644 --- a/date/date.h +++ b/date/date.h @@ -415,6 +415,11 @@ public: template bool ParseHourMin(const StringType & str); + template + bool ParseZoneOffset(const CStringType * str, const CStringType ** str_after = 0); + + template + bool ParseZoneOffset(const StringType & str); /* parsing hour and minutes (if exists) and seconds (if exists) @@ -507,7 +512,7 @@ private: void SkipWhite(const CStringType * & str); template - bool ReadInt(const CStringType * & str, int & result); + bool ReadInt(const CStringType * & str, int & result, size_t max_digits = 0); template bool SkipSeparator(const CStringType * & str, int separator, int separator2 = -1, int separator3 = -1); @@ -720,6 +725,67 @@ bool Date::ParseHourMin(const StringType & str) } +template +bool Date::ParseZoneOffset(const CStringType * str, const CStringType ** str_after) +{ + bool result = false; + bool is_sign = false; + int offset_hour = 0; + int offset_min = 0; + + SkipWhite(str); + + if( *str == '-' || *str == '+' ) + { + if( *str == '-' ) + is_sign = true; + + str += 1; + + if( ReadInt(str, offset_hour, 2) && offset_hour >= -12 && offset_hour <= 14 ) + { + SkipWhite(str); + SetAfter(str, str_after); + + if( *str == ':' ) + { + str += 1; + SkipWhite(str); + SetAfter(str, str_after); + } + + if( ReadInt(str, offset_min, 2) && offset_min > -60 && offset_min < 60 ) + { + SetAfter(str, str_after); + } + else + { + offset_min = 0; + } + + time_t offset = (time_t)offset_hour * 60 * 60 + (time_t)offset_min * 60; + result = true; + + if( is_sign ) + offset = -offset; + + FromTime(ToTime() - offset); + } + } + +return result; +} + + +template +bool Date::ParseZoneOffset(const StringType & str) +{ + return ParseZoneOffset(str.c_str()); +} + + + + template bool Date::ParseTime(const CStringType * str, const CStringType ** str_after) @@ -801,7 +867,6 @@ bool Date::Parse(const CStringType * str, const CStringType ** str_after) { const CStringType * after; bool result = false; -bool is_iso = false; if( ParseYearMonthDay(str, &after) ) { @@ -813,17 +878,22 @@ bool is_iso = false; // https://en.wikipedia.org/wiki/ISO_8601 // at the moment skip the 'T' character only after += 1; - is_iso = true; } if( ParseHourMinSec(after, &after) ) { + SkipWhite(after); result = true; - if( is_iso && *after == 'Z' ) + if( *after == 'Z' ) { after += 1; } + else + { + // we dont have to check errors here + ParseZoneOffset(after, &after); + } } } @@ -864,17 +934,19 @@ void Date::SkipWhite(const CStringType * & str) template -bool Date::ReadInt(const CStringType * & str, int & result) +bool Date::ReadInt(const CStringType * & str, int & result, size_t max_digits) { bool something_read = false; SkipWhite(str); result = 0; + size_t len = 0; - while( *str >= '0' && *str <= '9' ) + while( *str >= '0' && *str <= '9' && (max_digits == 0 || len < max_digits)) { result = result * 10 + (*str - '0'); str += 1; + len += 1; something_read = true; if( result > 10000 )