libanna.time refactoring
authorEduardo Ramos Testillano <eduardo.ramos.testillano@gmail.com>
Sun, 3 Aug 2014 00:30:56 +0000 (02:30 +0200)
committerEduardo Ramos Testillano <eduardo.ramos.testillano@gmail.com>
Sun, 3 Aug 2014 00:30:56 +0000 (02:30 +0200)
example/diameter/launcher/main.cpp
example/time/conversor/main.cpp
include/anna/time/Date.hpp
include/anna/time/functions.hpp
include/anna/time/internal/TZ.hpp [deleted file]
include/anna/time/internal/Timezone.hpp [new file with mode: 0644]
source/time/Date.cpp
source/time/functions.cpp
test/time/main.cpp

index 249a595..af3ceb0 100644 (file)
@@ -1173,7 +1173,7 @@ void Launcher::writeLogFile(const anna::diameter::codec::Message & decodedMessag
 
    if (a_detailedLog) {
       anna::time::Date now;
-      now.setCurrent();
+      now.setNow();
       title += " ";
       title += now.asString();
       log += anna::functions::highlight(title, anna::functions::TextHighlightMode::OverAndUnderline);
@@ -1289,7 +1289,7 @@ throw(anna::RuntimeException) {
    LOGMETHOD(anna::TraceMethod tm("Launcher", "run", ANNA_FILE_LOCATION));
    CommandLine& cl(anna::CommandLine::instantiate());
    // Start time:
-   a_start_time.setCurrent();
+   a_start_time.setNow();
    // Statistics:
    anna::statistics::Engine::instantiate().enable();
    ///////////////////////////////
index 371d907..5548764 100644 (file)
@@ -63,7 +63,7 @@ int main(int argc, char** argv) {
    if (!argv[1]) {
       std::string msg = "Use: ";
       msg += argv[0];
-      msg += " [-unix <unix timestamp>] [-ntp <ntp timestamp>] [-yyyymmddHHmmss <yyyymmddHHmmss>]";
+      msg += " [-unix <unix timestamp>] [-ntp <ntp timestamp>] [-yyyymmddHHmmss <yyyymmddHHmmss (in the system timezone)>]";
       F_exit(msg.c_str());
    }
 
index 8d699ff..f0a46be 100644 (file)
@@ -44,7 +44,7 @@
 #include <time.h>
 
 // Local
-#include <anna/time/internal/TZ.hpp>
+#include <anna/time/internal/Timezone.hpp>
 
 
 namespace anna {
@@ -56,27 +56,14 @@ class Node;
 //------------------------------------------------------------------------------
 //---------------------------------------------------------------------- #define
 //------------------------------------------------------------------------------
-#define _2K38_EFFECT_LIMIT "20380119031407" // UTC
-
-// Era Unix:  01/01/1970 00:00:00 UTC
-// Fecha NTP: 01/01/1900 00:00:00 UTC
-// -> Segundos de 70 años ( de 1900 a 1970) : 2207520000
-// -> Entre 1900 y 1970 hay 17años bisiestos, por lo que hay que sumar 17 días: 1468800 Segundos
-// TOTAL = 2207520000 + 1468800 :
-// Significa que debemos restar el anterior valor para obtener un valor unix, y sumarlo para tener un timestamp NTP:
-#define TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970   2208988800U
-
-// The NTP timestamp format represents seconds and fraction as a 64-bit unsigned fixed-point
-// integer with decimal point to the left of bit 32 numbered from the left. The 32-bit seconds
-// field spans about 136 years, while the 32-bit fraction field precision is about 232 picoseconds.
-
-// Para un timestamp NTP me bastan 32 bits, es decir 'unsigned int'. El tipo time_t es realmente un int. Cojo
-// el mayor entre ambos: unsigned int.
-
-
-#define STRING_FORMAT_yyyymmddHHmmss         "%04d%02d%02d%02d%02d%02d"
-#define STRPTIME_FORMAT_yyyy_mm_dd_HH_mm_ss  "%Y-%m-%d-%H-%M-%S"
 
+// Unix time reference:  01/01/1970 00:00:00 UTC
+// NTP time reference:   01/01/1900 00:00:00 UTC
+// -> 70 years have 2207520000 seconds.
+// -> Between 1900 and 1970 there are 17 leap years: 1468800 seconds more (17 days)
+// TOTAL DIFFERENCE = 2207520000 + 1468800 = 2208988800
+#define TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970   2208988800U
+//#define _2K38_EFFECT_LIMIT                       "20380119031407" // UTC
 
 
 namespace anna {
@@ -87,72 +74,64 @@ namespace time {
 /**
 * Absolute time representation structs class manager.
 * Allow any time assignment/extraction regarding any timezone.
+* Uses shell TZ assignment or rely on system timezone configuration (in ubuntu, /etc/timezone
+* stores the abbreviation and /etc/localtime keeps the timezone file from /usr/share/zoneinfo).
 *
-* Certain methods could launch runtime exception when trying to get TZ from shell.
+* The internal unix timestamp reamain constant and thedate representation depends on the
+* configured timezone. Some store methods could specify a certain origin timezone, but the
+* instance inner timezone won't be changed until the user want to do that.
 *
 * <pre>
 *
-* I.e., supose you have TZ="MET" on host (on Madrid):
+*  Sample code:
 *
-*   resources::time::Date edu_birth("CET");
-*   //resources::time::Date edu_birth; // if Context TZ = shell TZ = "CET"
-*   edu_birth.store ("19741219101500");
-*   std::cout << "'edu_birth.asString()' is: " << edu_birth.asString() << std::endl;
-*   std::cout << "'Timestamp' edu_birth (Madrid:CET): " << edu_birth.getUnixTimestamp() << std::endl;
-*   struct tm Tm = edu_birth.getTm();
-*   std::cout << "'Tm' edu_birth (madrid:CET): " << "tm_mday = " << Tm.tm_mday << ", tm_mon (0-11) = " << Tm.tm_mon
-*   << ", tm_year (since 1900) = " << Tm.tm_year << ", tm_hour = " << Tm.tm_hour
-*   << ", tm_min = " << Tm.tm_min << ", tm_sec = " << Tm.tm_sec << std::endl;
-*   resources::time::Date same_moment_canary_island("GMT");
-*   same_moment_canary_island.store (edu_birth.getUnixTimestamp());
-*   std::cout << "'yyyymmddHHmmss' for 'same_moment_canary_island': " << (same_moment_canary_island.yyyymmddHHmmss()).c_str() << std::endl;
-*   edu_birth.setTzContext ("GMT");
-*   std::cout << "'yyyymmddHHmmss' for edu_birth, Local time on Canary Island: " << (edu_birth.yyyymmddHHmmss()).c_str() << std::endl;
-*   resources::time::Date birthday("EET");
-*   birthday.store (same_moment_canary_island.getTm(), "GMT"); // TZ origin = "GMT"
-*   if (birthday == edu_birth)
-*   {
-*   std::cout << "'birthday' same as 'edu_birth', and 'yyyymmddHHmmss' is: " << (birthday.yyyymmddHHmmss()).c_str()
-*   << " in TZ = " << (birthday.getTzContext()).getValue().c_str() << std::endl;
-*   }
+*  anna::time::functions::initialize();
+*  std::cout << "SystemTimezone: " << anna::time::functions::getSystemTimezone().asString() << std::endl;
 *
-*   std::cout << "'birthday': " << birthday.asString() << std::endl;
-*   std::cout << "'edu_birth': " << edu_birth.asString() << std::endl;
+*  anna::time::Date myBirth ("CET");
+*  myBirth.store("19741219111500", "EET");
+*  std::cout << "myBirth: " << myBirth.asString() << std::endl;
 *
-*   edu_birth.setTzContext (resources::time::functions::getLocalTz().getValue().c_str());
-*   std::cout << "'edu_birth' on local TZ: " << edu_birth.asString() << std::endl;
+*  anna::time::Date same_moment_canary_island("GMT");
+*  same_moment_canary_island.store(myBirth.getUnixTimestamp());
+*  std::cout << "same_moment_canary_island: " << same_moment_canary_island.asString() << std::endl;
+*  myBirth.setTz("GMT");
+*  std::cout << "myBirth on GMT: " << myBirth.asString() << std::endl;
+*  std::cout << "EQUAL: same_moment_canary_island = " << same_moment_canary_island.yyyymmddHHmmss() << "; myBirth in context GMT = " << myBirth.yyyymmddHHmmss() << std::endl;
+*  same_moment_canary_island.setTz("CET");
+*  std::cout << "same_moment_canary_island on CET: " << same_moment_canary_island.asString() << std::endl;
+*  anna::time::Date birthday("EET");
+*  birthday.store(same_moment_canary_island.getTm(), "CET");
+*  std::cout << "EQUAL: birthday TS = " << birthday.getUnixTimestamp() << "; myBirth TS = " << myBirth.getUnixTimestamp() << std::endl;
+*  std::cout << "birthday EET = " << birthday.asString() << std::endl;
 *
-*   //birthday.setTzContext("CET");
-*   birthday.setTzContext (resources::time::functions::getLocalTz().getValue().c_str()); // Go from "EET" to "CET"
-*   std::cout << "'yyyymmddHHmmss' for 'birthday' on Local TZ: " << (birthday.yyyymmddHHmmss()).c_str() << std::endl;
-*   // Adding 18 years to 'edu_birth':
-*   Tm.tm_year += 18;
-*   resources::time::Date eighteen("CET");
-*   eighteen.store (Tm);
-*   if (eighteen >= same_moment_canary_island) // same as compare to 'edu_birth'
-*   {
-*   std::cout << "'eighteen' is 'yyyymmddHHmmss' = " << (eighteen.yyyymmddHHmmss()).c_str() << std::endl;
-*   std::cout << "'eighteen' is later than timestamp for 'same_moment_canary_island' = " << same_moment_canary_island.getUnixTimestamp() << std::endl;
-*   std::cout << "'eighteen' is later than timestamp for 'edu_birth' = " << edu_birth.getUnixTimestamp() << std::endl;
-*   }
+*  std::cout << "Setting Local timezone ..." << std::endl;
+*  myBirth.setSystemTimezone();
+*  birthday.setSystemTimezone();
+*  std::cout << "EQUAL: birthday " << birthday.asString() << "; myBirth " << myBirth.asString() << std::endl;
+*  std::cout << "EQUAL: birthday (Local Timezone)= " << birthday.yyyymmddHHmmss() << "; myBirth (Local Timezone)= " << myBirth.yyyymmddHHmmss() << std::endl;
+*  std::cout << "myBirth TZ  = " << myBirth.getTzAsString() << std::endl;
+*  std::cout << "birthday TZ  = " << myBirth.getTzAsString() << std::endl;
 *
+*  myBirth.setTz("GMT");
+*  std::cout << "myBirth in GMT = " << myBirth.yyyymmddHHmmss() << std::endl;
 *
-* -----------------------------------------------------------------------------------------------------------------------------
-* Program output:
+*  Program output:
 *
-*   'edu_birth.asString()' is: 19/12/1974 10:15:00 CET, isdst = 0 [Unix Timestamp: 156676500], Local TZ = EET
-*   'Timestamp' edu_birth (Madrid:CET): 156676500
-*   'Tm' edu_birth (madrid:CET): tm_mday = 19, tm_mon (0-11) = 11, tm_year (since 1900) = 74, tm_hour = 10, tm_min = 15, tm_sec = 0
-*   'yyyymmddHHmmss' for 'same_moment_canary_island': 19741219091500
-*   'yyyymmddHHmmss' for edu_birth, Local time on Canary Island: 19741219091500
-*   'birthday' same as 'edu_birth', and 'yyyymmddHHmmss' is: 19741219111500 in TZ = EET
-*   'birthday': 19/12/1974 11:15:00 EET, isdst = 0 [Unix Timestamp: 156676500], Local TZ = EET
-*   'edu_birth': 19/12/1974 09:15:00 GMT, isdst = 0 [Unix Timestamp: 156676500], Local TZ = EET
-*   'edu_birth' on local TZ: 19/12/1974 10:15:00 EET, isdst = 0 [Unix Timestamp: 156676500], Local TZ = EET
-*   'yyyymmddHHmmss' for 'birthday' on Local TZ: 19741219101500
-*   'eighteen' is 'yyyymmddHHmmss' = 19921219101500
-*   'eighteen' is later than timestamp for 'same_moment_canary_island' = 156676500
-*   'eighteen' is later than timestamp for 'edu_birth' = 156676500
+*  SystemTimezone: <TZ unset\>
+*  myBirth: Thursday 19/12/1974 10:15:00 CET, isdst = 0 [Unix Timestamp: 156676500, Ntp Timestamp: 2365665300], System Timezone: <TZ unset\>
+*  same_moment_canary_island: Thursday 19/12/1974 09:15:00 GMT, isdst = 0 [Unix Timestamp: 156676500, Ntp Timestamp: 2365665300], System Timezone: <TZ unset\>
+*  myBirth on GMT: Thursday 19/12/1974 09:15:00 GMT, isdst = 0 [Unix Timestamp: 156676500, Ntp Timestamp: 2365665300], System Timezone: <TZ unset\>
+*  EQUAL: same_moment_canary_island = 19741219091500; myBirth in context GMT = 19741219091500
+*  same_moment_canary_island on CET: Thursday 19/12/1974 10:15:00 CET, isdst = 0 [Unix Timestamp: 156676500, Ntp Timestamp: 2365665300], System Timezone: <TZ unset\>
+*  EQUAL: birthday TS = 156676500; myBirth TS = 156676500
+*  birthday EET = Thursday 19/12/1974 11:15:00 EET, isdst = 0 [Unix Timestamp: 156676500, Ntp Timestamp: 2365665300], System Timezone: <TZ unset\>
+*  Setting Local timezone ...
+*  EQUAL: birthday Thursday 19/12/1974 10:15:00 <TZ unset\>, isdst = 0 [Unix Timestamp: 156676500, Ntp Timestamp: 2365665300], System Timezone: <TZ unset\>; myBirth Thursday 19/12/1974 10:15:00 <TZ unset\>, isdst = 0 [Unix Timestamp: 156676500, Ntp Timestamp: 2365665300], System Timezone: <TZ unset\>
+*  EQUAL: birthday (Local Timezone)= 19741219101500; myBirth (Local Timezone)= 19741219101500
+*  myBirth TZ  = <TZ unset\>
+*  birthday TZ  = <TZ unset\>
+*  myBirth in GMT = 19741219091500
 *
 * </pre>
 */
@@ -163,134 +142,113 @@ class Date {
   /////////////////////////////////////////////////
 
   // Main data:
-  TZ a_TZ_context;          // timezone for current representation
-  time_t a_unix_timestamp;  // unix timestamp
+  Timezone a_tz;            // timezone for this instance context
+  time_t a_timestamp; // unix timestamp
 
   // Secondary data:
-  struct tm a_tm_struct;
-  std::string _yyyymmddHHmmss;        // string representation for 'tm'
+  struct tm a_tm;
 
-  // Auxiliar:
-  TZ a_local_tz;          // local tz on host
-  TZ a_work_tz;           // auxiliar tz
 
-  void _putenv(const char * Tz) throw();
-  void set_tz_context(const char * TzContext) throw();
-  const TZ & get_TZ_context(void) const throw();
-  void _initialize(const char * TzContext) throw();
+  // sets the current date/time (time(NULL)) and provided TimeZone as described in constructor
+  void initialize(const char *TZ = NULL) throw();
 
-  void check_yyyymmddHHmmss(const std::string & yyyymmddHHmmss) throw(anna::RuntimeException);
-  void refresh_regarding_unix_timestamp(void) throw();   // main refresh method
+  // main refresh method regarding timestamp
+  void refresh(void) throw();
 
   anna::Mutex a_mutex;
+
 public:
 
   /**
   * Default Constructor
+  * @param TZ timezone for date/time representation. Default (NULL) assumes the system
+  * timezone configuration. Empty string will be interpreted as UTC timezone.
   */
-  Date(const char * TzContext = NULL);
+  Date(const char *TZ = NULL);
 
   /**
   * Copy Constructor
   */
-  Date(const Date & d);
+  Date(const Date & d) { *this = d; }
 
   /**
   * Destructor
   */
-  ~Date();
-
+  ~Date() {;}
 
-  // sets
 
+  // setters
 
   /**
-  * Class initialization with current date/time (time(NULL)) and provided TimeZone (default is Local TimeZone)
-  *
-  * @param TzContext timezone for date/time representation. Default is Local timezone
-  *
-  * @see setTzContext()
-  * @see store()
+  * Sets the current date/time (time(NULL)) and provided TimeZone as described in constructor
   */
-  void initialize(const char * TzContext = NULL) throw();
+  void setNow(const char *TZ = NULL) throw() { initialize(TZ); }
 
 
   /**
-  * Same as initialize()
+  * Sets the provided timezone for date/time representation of the class instance.
+  * This method keeps invariant the unix timestamp, thus, the date representation
+  *  will evolve depending on the configured timezone.
+  * @warning Be careful with incorrect TZ values because no error will be shown but
+  * dates could be misleading. The valid TZ could be seen with tzselect tool or
+  * directly looking at /usr/share/zoneinfo hierarchy.
+  *
+  * @param TZ timezone for date/time representation.
+  * Default (NULL) is the local host (user-supplied) timezone
+  * Empty string sets UTC0 (GMT, Greenwich)
+  * Use available timezones in /usr/share/zoneinfo; i.e.: Europe/Madrid, CET, etc.
+  * You can also use 'tzselect' helper, but that tool don't change the system
+  * timezone, only helps to know the valid TZ values and shows how to change
+  * the timezone settings if you would want to do that).
   */
-  void setCurrent(const char * TzContext = NULL) throw() { initialize(TzContext); }
+  void setTz(const char *TZ = NULL) throw();
 
 
   /**
-  * Sets the provided timezone for date/time representation. default is Local timezone.
-  *
-  * @param TzContext timezone for date/time representation. Default is Local timezone
-  *
-  * @see initialize()
-  * @see store()
+   Sets the local host timezone (even if it is based on TZ or in /usr/share/zoneinfo)
   */
-  void setTzContext(const char * TzContext = NULL) throw();
+  void setSystemTimezone() throw();
 
 
   /**
-  * Sets date/time from string 'yyyymmddHHmmss' representation (HH is 24 hour format, and string must be 14 digits-length),
-  * and optional timezone (default is local)
-  *
-  * @param yyyymmddHHmmss 'yyyymmddHHmmss' date/time
-  * @param OriginTz timezone for date/time provided. Default is Local TZ
-  *
-  * @see initialize()
-  * @see setTzContext()
-  */
-  void store(const std::string & yyyymmddHHmmss, const char * OriginTz = NULL) throw(anna::RuntimeException);
-
-
-  /**
-  * Sets date/time from string representation with certain provided format, and optional timezone (default is local)
-  *
-  * @param dateTimeAsStringFormat Date/time string format
-  * @param dateTimeAsString Date/time string
-  * @param OriginTz timezone for date/time provided. Default is Local TZ
+  * Sets date/time providing unix timestamp (seconds since 01-Jan-1970 GMT)
   *
-  * @see initialize()
-  * @see setTzContext()
+  * @param unixTimestamp Time since 01-Jan-1970 GMT
   */
-  void store(const char* dateTimeAsStringFormat, const std::string & dateTimeAsString, const char * OriginTz = NULL) throw(anna::RuntimeException);
+  void store(const time_t & unixTimestamp) throw();
+  void storeUnix(const time_t & unixTimestamp) throw() { store(unixTimestamp); }
 
 
   /**
-  * Sets date/time from standard (time.h) 'tm' struct and optional timezone (default is local)
-  *
-  * @param TmOrigen 'tm' struct date/time
-  * @param OriginTz timezone for date/time provided. Default is Local TZ
+  * Sets date/time providing ntp timestamp (seconds since 01-Jan-1900 GMT)
   *
-  * @see initialize()
-  * @see setTzContext()
+  * @param ntpTimestamp Time since 01-Jan-1900 GMT
   */
-  void store(const struct tm & TmOrigen, const char * OriginTz = NULL) throw(anna::RuntimeException);
+  void storeNtp(const unsigned int &ntpTimestamp) throw();
 
 
   /**
-  * Sets date/time providing unix timestamp (seconds since 01-Jan-1970 GMT)
-  *
-  * @param unixTimestamp Time since 01-Jan-1970 GMT
+  * Sets date/time from standard 'tm' struct and optional timezone
   *
-  * @see initialize()
-  * @see setTzContext()
+  * @param date 'tm' struct date/time
+  * @param TZ timezone for date/time provided. Default (NULL) assumes the system
+  * timezone configuration. Empty string will be interpreted as UTC timezone.
   */
-  void store(const time_t & unixTimestamp) throw();
-  void storeUnix(const time_t & unixTimestamp) throw() { store(unixTimestamp); }
+  void store(const struct tm &date, const char *TZ = NULL) throw(anna::RuntimeException);
 
 
   /**
-  * Sets date/time providing ntp timestamp (seconds since 01-Jan-1900 GMT)
-  *
-  * @param ntpTimestamp Time since 01-Jan-1900 GMT
-  *
-  * @see initialize()
-  * @see setTzContext()
+  * Sets date/time from string representation with certain provided format,
+  * and optional timezone
+  *
+  * @param stringDate Date/time string
+  * @param TZ timezone for date/time provided. Default (NULL) assumes the system
+  * timezone configuration. Empty string will be interpreted as UTC timezone.
+  * @param strptimeFormat Date/time string format for strptime primitive.
+  * See format syntax at http://man7.org/linux/man-pages/man3/strptime.3.html
   */
-  void storeNtp(const unsigned int & ntpTimestamp) throw();
+  void store(const std::string &stringDate, const char *TZ = NULL, const char *strptimeFormat = "%Y%m%d%H%M%S") throw(anna::RuntimeException);
+  //void store(const std::string &stringDate, const char *tz = NULL, const char *strptimeFormat = "%Y-%m-%d-%H-%M-%S") throw(anna::RuntimeException);
 
 
   /**
@@ -298,7 +256,7 @@ public:
   *
   * @param d Source class instance
   *
-  * @return Retunrs copied reference
+  * @return Returns copied reference
   */
   Date & operator = (const Date &d);
 
@@ -356,76 +314,68 @@ public:
 
 
   /**
-  * Gets context representation TZ
+  * Gets context instance timezone information
   *
-  * @return context representation TZ
-  *
-  * @see yyyymmddHHmmss()
-  * @see getUnixTimestamp()
-  * @see getTm()
-  * @see asString()
+  * @return  NULL if TZ is unset, or string for TZ environment variable
+  * (empty is allowed and use to be understood as UTC.
   */
-  const std::string & getTzContext(void) const throw();
+  const char *getTz(void) const throw() { return (a_tz.unsetTZ() ? NULL:a_tz.getValue().c_str()); }
 
 
   /**
-  * Gets 'yyyymmddHHmmss' stored data
-  *
-  * @return Time/date on format 'yyyymmddHHmmss'
-  *
-  * @see getTzContext()
-  * @see getUnixTimestamp()
-  * @see getTm()
-  * @see asString()
+  * Gets the context timezone as string
   */
-  const std::string & yyyymmddHHmmss(void) const throw();
+  std::string getTzAsString() const throw() { return a_tz.asString(); }
 
 
   /**
-  * Gets unix timestamp (01-Jan-1970 GMT)
+  * Gets 'tm' struct on the current timezone
   *
-  * @return Seconds since 01-Jan-1970 GMT
+  * @return 'tm' struct on the current timezone
+  */
+  const struct tm & getTm(void) const throw() { return a_tm; }
+
+  /**
+  * Gets the week day abbreviation: Sun, Mon, Tue, Wed, Thu, Fri, Sat
   *
-  * @see getTzContext()
-  * @see yyyymmddHHmmss()
-  * @see getTm()
-  * @see asString()
+  * @return Day of the week
   */
-  const time_t & getUnixTimestamp(void) const throw();
+  const char *getDay(void) const throw();
 
 
   /**
-  * Gets ntp timestamp (01-Jan-1900 GMT)
+  * Gets 'yyyymmddHHmmss' representation for the current timezone
   *
-  * @return Seconds since 01-Jan-1900 GMT
+  * @return Time/date on format 'yyyymmddHHmmss'
   *
-  * @see getTzContext()
-  * @see yyyymmddHHmmss()
-  * @see getTm()
-  * @see asString()
+  * @see getTz
   */
-  unsigned int getNtpTimestamp(void) const throw();
+  std::string yyyymmddHHmmss(void) const throw();
 
 
   /**
-  * Gets 'tm' struct on context representation TZ
+  * Gets unix timestamp (01-Jan-1970 GMT)
   *
-  * @return 'tm' struct on context representation TZ
+  * @return Seconds since 01-Jan-1970 GMT
+  */
+  const time_t & getUnixTimestamp(void) const throw() { return a_timestamp; }
+
+
+  /**
+  * Gets ntp timestamp (01-Jan-1900 GMT)
   *
-  * @see getTzContext()
-  * @see yyyymmddHHmmss()
-  * @see getUnixTimestamp()
-  * @see asString()
+  * @return Seconds since 01-Jan-1900 GMT
   */
-  const struct tm & getTm(void) const throw();
+  unsigned int getNtpTimestamp(void) const throw() {
+    unsigned int ntp_timestamp = a_timestamp + TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970;
+    return ntp_timestamp;
+  }
 
 
   /**
   * Class string representation
   *
   * @return String with class content
-  *
-  * @see asXML()
   */
   std::string asString(void) const throw();
 
@@ -434,8 +384,6 @@ public:
   * Class XML representation
   *
   * @return XML with class content
-  *
-  * @see asString()
   */
   anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
 
index 67ab412..47a89bd 100644 (file)
@@ -44,7 +44,7 @@ namespace anna {
 
 namespace time {
 
-class TZ;
+class Timezone;
 
 class functions {
 public:
@@ -79,9 +79,9 @@ public:
   static bool initialized(void) throw();
 
   /**
-     Gets the local TZ
+     Gets the host user-supplied timezone configuration
   */
-  static const TZ & getLocalTz(void) throw();
+  static const Timezone & getSystemTimezone(void) throw();
 
 
   /**
diff --git a/include/anna/time/internal/TZ.hpp b/include/anna/time/internal/TZ.hpp
deleted file mode 100644 (file)
index 84638fe..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-// ANNA - Anna is Not Nothingness Anymore
-//
-// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
-//
-// https://bitbucket.org/testillano/anna
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions
-// are met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Authors: eduardo.ramos.testillano@gmail.com
-//          cisco.tierra@gmail.com
-
-
-#ifndef anna_time_internal_TZ_hpp
-#define anna_time_internal_TZ_hpp
-
-
-// Standard
-#include <string>
-
-
-//------------------------------------------------------------------------------
-//---------------------------------------------------------------------- #define
-//------------------------------------------------------------------------------
-
-
-namespace anna {
-
-namespace time {
-
-class TZ {
-
-  bool a_initialized;
-  std::string a_value;
-  bool a_isUnset;
-
-public:
-
-  TZ() { a_initialized = false; };
-  ~TZ() {};
-
-
-  // sets
-
-  void set(const char *input) {
-    a_initialized = true;
-    a_value = input ? input : "";
-    a_isUnset = !input;
-  }
-
-  TZ & operator = (const TZ &tz) {
-    if(this == &tz) return (*this);
-
-    a_initialized = tz.isInitialized();
-    a_value = tz.getValue();
-    a_isUnset = tz.isUnset();
-    return (*this);
-  }
-
-  // gets
-
-  // Operators
-
-  friend bool operator == (const TZ & tz1, const TZ & tz2) {
-    if(tz1.isInitialized() != tz2.isInitialized())
-      return (false);
-
-    if(tz1.isUnset())
-      return (tz2.isUnset());
-
-    return (tz1.getValue() == tz2.getValue());
-  }
-
-  friend bool operator != (const TZ & tz1, const TZ & tz2) {
-    return (!(tz1 == tz2));
-  }
-
-  const std::string & getValue(void) const throw() {
-    return (a_value);
-  }
-
-
-  bool isInitialized(void) const throw() {
-    return (a_initialized);
-  }
-
-
-  bool isUnset(void) const throw() { return (a_isUnset); }
-  bool isEmpty(void) const throw() { return (getValue() == ""); }
-
-  std::string getShellAssignment(void) const throw() {
-    std::string assignment;
-
-    if(isUnset())
-      assignment = "unset TZ";
-    else {
-      assignment = "TZ=";
-      assignment += getValue();
-    }
-
-    return (assignment);
-  }
-
-};
-
-
-}
-}
-
-#endif
-
diff --git a/include/anna/time/internal/Timezone.hpp b/include/anna/time/internal/Timezone.hpp
new file mode 100644 (file)
index 0000000..ed12614
--- /dev/null
@@ -0,0 +1,164 @@
+// ANNA - Anna is Not Nothingness Anymore
+//
+// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
+//
+// https://bitbucket.org/testillano/anna
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: eduardo.ramos.testillano@gmail.com
+//          cisco.tierra@gmail.com
+
+
+#ifndef anna_time_internal_Timezone_hpp
+#define anna_time_internal_Timezone_hpp
+
+
+// Standard
+#include <string>
+#include <stdlib.h>
+#include <iostream>
+
+extern char *tzname[2];
+
+//------------------------------------------------------------------------------
+//---------------------------------------------------------------------- #define
+//------------------------------------------------------------------------------
+
+
+namespace anna {
+
+namespace time {
+
+class Timezone {
+
+  bool a_initialized;
+  std::string a_value;
+  bool a_unsetTZ;
+
+public:
+
+  Timezone() { a_initialized = false; };
+  ~Timezone() {};
+
+
+  // sets
+  // pass NULL to unset
+  void set(const char *input) {
+    a_initialized = true;
+    a_value = input ? input : "";
+
+  //  /*
+  //    In many C libraries, TZ='' is equivalent to TZ='GMT0' or TZ='UTC0',
+  //    and that's the behavior you're observing. An unset TZ is equivalent
+  //    to a system-supplied default, typically the local time where the host
+  //    is physically located.
+  //  */
+  //  if (input && (a_value == "")) a_value="UTC0";
+
+    a_unsetTZ = !input;
+  }
+
+  Timezone & operator = (const Timezone &tz) {
+    if(this == &tz) return (*this);
+
+    a_initialized = tz.isInitialized();
+    a_value = tz.getValue();
+    a_unsetTZ = tz.unsetTZ();
+    return (*this);
+  }
+
+  // gets
+
+  // Operators
+
+  friend bool operator == (const Timezone & tz1, const Timezone & tz2) {
+    if(tz1.isInitialized() != tz2.isInitialized())
+      return (false);
+
+    if(tz1.unsetTZ())
+      return (tz2.unsetTZ());
+
+    return (tz1.getValue() == tz2.getValue());
+  }
+
+  friend bool operator != (const Timezone & tz1, const Timezone & tz2) {
+    return (!(tz1 == tz2));
+  }
+
+  // be careful: empty if unset
+  const std::string & getValue(void) const throw() {
+    return (a_value);
+  }
+
+
+  bool isInitialized(void) const throw() {
+    return (a_initialized);
+  }
+
+  //Unset is when getenv("TZ") returns NULL. Then, /etc/localtime used to be a copy or symlink to
+  // any of the /usr/share/zoneinfo available timezones.
+  bool unsetTZ(void) const throw() { return (a_unsetTZ); }
+
+  bool apply() const throw() {
+    //    http://stackoverflow.com/questions/5873029/questions-about-putenv-and-setenv
+    if(unsetTZ()) {
+      unsetenv("TZ");                                                             
+    }                                                                             
+    else {                                                                        
+      setenv("TZ", a_value.c_str(), 1 /* overwrite */);                              
+
+      /*
+      // If TZ has an invalid setting, tzset() uses GMT0:
+      // Check it:
+      tzset();
+      //std::cout << "tzname[0]: " << tzname[0] << std::endl;
+      //std::cout << "tzname[1]: " << tzname[1] << std::endl;
+      std::string tzname_1 = tzname[1];
+      bool success = (tzname_1 != "");
+      if (!success) std::cerr << "Invalid TZ '" << a_value << "'. Probably GMT0 is going to be used instead !" << std::endl;
+      return success;
+      */
+    }                                                                             
+
+    return true;
+  }
+
+  std::string asString() const throw() {
+    std::string result = getValue();
+    if (unsetTZ()) return "<TZ unset>";
+    if (result == "") return "<TZ empty>";
+    return result;
+  }
+};
+
+
+}
+}
+
+#endif
+
index fa6c8c3..e09a589 100644 (file)
@@ -60,312 +60,146 @@ using namespace anna::time;
 //------------------------------------------------------------------------- Date
 //******************************************************************************
 
-//------------------------------------------------------------------------------
-//----------------------------------------------------------------- Date::Date()
-//------------------------------------------------------------------------------
-Date::Date(const char * TzContext) {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "Default Constructor", ANNA_FILE_LOCATION));
-  time::sccs::activate();
-
-  if(!functions::initialized()) {
-    //anna::Logger::error("You should firstly invoke anna::time::functions::initialize() before using this module", ANNA_FILE_LOCATION);
-    //Perhaps former couldn't be written (no Logger initialize):
-    std::cout << std::endl << "Develop ERROR: you should firstly invoke anna::time::functions::initialize() before using time module" << std::endl;
-  }
-
-  a_local_tz = functions::getLocalTz();
-  a_work_tz = a_local_tz;
-  initialize(TzContext);
-};
-
-
-//------------------------------------------------------------------------------
-//----------------------------------------------------------------- Date::Date()
-//------------------------------------------------------------------------------
-Date::Date(const Date & d) {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "Copy constructor", ANNA_FILE_LOCATION));
-  time::sccs::activate();
-  *this = d;
-  a_local_tz = functions::getLocalTz();
-  a_work_tz = d.a_work_tz;
-};
-
-
-//------------------------------------------------------------------------------
-//---------------------------------------------------------------- Date::~Date()
-//------------------------------------------------------------------------------
-Date::~Date() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "~Date", ANNA_FILE_LOCATION));
-}
-
 // private:
 
-
 //------------------------------------------------------------------------------
-//-------------------------------------------------------------- Date::_putenv()
+//----------------------------------------------------------- Date::initialize()
 //------------------------------------------------------------------------------
-void Date::_putenv(const char * Tz) throw() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "_putenv", ANNA_FILE_LOCATION));
-  TZ providedTz;
-
-  if(Tz)
-    providedTz.set(Tz);
-  else
-    providedTz = a_local_tz;
-
-  if(providedTz != a_work_tz) {
-    a_work_tz = providedTz;
-// Solaris no tiene el unsetenv, actualizamos directamente con putenv: "unset TZ", que es totalmente valido (*)
-//      if (a_work_tz.isUnset())
-//         unsetenv ("TZ");
-//      else
-    putenv((char *)a_work_tz.getShellAssignment().c_str());
-// (*)
-//      if (a_work_tz.isUnset())
-//         std::cout << "Unset" << std::endl;
-//      else
-//      {
-//         if (a_work_tz.isEmpty())
-//            std::cout << "Empty" << std::endl;
-//         else
-//            std::cout << a_work_tz.getValue() << std::endl;
-//      }
-//         std::cout << "Salida putenv poniendo " << a_work_tz.getAssignment().c_str() << ": " << putenv((char *)a_work_tz.getAssignment().c_str()) << std::endl;
-//         const char *kk = getenv("TZ");
-//         if (kk) std::cout << "getenv: " << kk << std::endl;
-//         else std::cout << "getenv: NULL" << std::endl;
-  }
+void Date::initialize(const char * TZ) throw() {
+  a_timestamp = ::time(NULL);
+  setTz(TZ);
 }
 
 
 //------------------------------------------------------------------------------
-//------------------------------------------------------- Date::set_tz_context()
+//-------------------------------------------------------------- Date::refresh()
 //------------------------------------------------------------------------------
-void Date::set_tz_context(const char * TzContext) throw() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "set_tz_context", ANNA_FILE_LOCATION));
-  if(TzContext)
-    a_TZ_context.set(TzContext);
-  else
-    a_TZ_context = a_local_tz;
-
-  refresh_regarding_unix_timestamp(); // borns with timestamp and is based on new TZ value
-}
+void Date::refresh(void) throw() {
+  anna::Guard guard(a_mutex);
 
+  // Set current/programmed timezone
+  a_tz.apply();
 
-//------------------------------------------------------------------------------
-//------------------------------------------------------- Date::get_TZ_context()
-//------------------------------------------------------------------------------
-const TZ & Date::get_TZ_context(void) const throw() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "get_TZ_context", ANNA_FILE_LOCATION));
-  return (a_TZ_context);
+  // Rescue info:
+  struct tm *ptrTm = localtime(&a_timestamp);
+  a_tm = *ptrTm;
 }
 
 
-//------------------------------------------------------------------------------
-//---------------------------------------------------------- Date::_initialize()
-//------------------------------------------------------------------------------
-void Date::_initialize(const char * TzContext) throw() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "_initialize", ANNA_FILE_LOCATION));
-  a_unix_timestamp = ::time(NULL);
-  set_tz_context(TzContext);  // This refresh all data with the asigned TZ
-}
 
+// public:
 
 //------------------------------------------------------------------------------
-//------------------------------------------------- Date::check_yyyymmddHHmmss()
+//----------------------------------------------------------------- Date::Date()
 //------------------------------------------------------------------------------
-void Date::check_yyyymmddHHmmss(const std::string & yyyymmddHHmmss)
-
-throw(anna::RuntimeException)
+Date::Date(const char *TZ) {
+  time::sccs::activate();
 
-{
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "check_yyyymmddHHmmss", ANNA_FILE_LOCATION));
-  // check 2038 effect: restrictive limit
-  if(yyyymmddHHmmss > _2K38_EFFECT_LIMIT) {  // ESTO NO LO COMPRUEBA mktime !!
-    throw anna::RuntimeException("Provided time/date is over 2K38 effect (19 January 2038, 03:14:07) !!", ANNA_FILE_LOCATION);
+  if(!functions::initialized()) {
+    std::cerr << std::endl << "Develop ERROR: you should firstly invoke anna::time::functions::initialize() before using time module" << std::endl;
   }
 
-  // check 14-digit length (i.e. "19741219100000")
-  int longitud = yyyymmddHHmmss.length();
-
-  if(longitud != 14) {
-    throw anna::RuntimeException("Provided time/date has not 14-digit length !!. Remember: 'yyyymmddHHmmss'", ANNA_FILE_LOCATION);
-  }
+  initialize(TZ);
+};
 
-  // All digits:
-  const char * ptr_cad = yyyymmddHHmmss.c_str();
 
-  for(register int k = 0; k < longitud; k++) {
-    if(!isdigit(ptr_cad[k])) {
-      throw anna::RuntimeException("Provided time/date only can contain digits !!. Remember: 'yyyymmddHHmmss'", ANNA_FILE_LOCATION);
-    }
-  }
+//------------------------------------------------------------------------------
+//---------------------------------------------------------------- Date::setTz()
+//------------------------------------------------------------------------------
+void Date::setTz(const char * TZ) throw() {
+  if (TZ) a_tz.set(TZ);
+  else a_tz = functions::getSystemTimezone(); 
 
-//   // Data range:
-//   int year, mon, mday, hour, min, sec;
-//   sscanf(ptr_cad, STRING_FORMAT_yyyymmddHHmmss, &year, &mon, &mday, &hour, &min, &sec);
-//   //year 2038 already checked
-//   if (mon < 1 || mon > 12)
-//      throw anna::RuntimeException("Month out of range (1-12) !!", ANNA_FILE_LOCATION);
-//   top_day = 31;
-//   if (mon == 2) top_day = 29/*28*/;
-//   if (mon == 4 || mon == 6 || mon == 9 || mon == 11) top_day = 30;
-//
-//   if (mday < 1 || mday > top_day)
-//      throw anna::RuntimeException(anna::functions::asString("Day out of range (1-%d) !!", top_day), ANNA_FILE_LOCATION);
-//   if (hour > 23)
-//      throw anna::RuntimeException("Hour out of range (0-23) !!", ANNA_FILE_LOCATION);
-//   if (min < 0 || min > 59)
-//      throw anna::RuntimeException("Minute out of range (0-59) !!", ANNA_FILE_LOCATION);
-//   if (sec < 0 || sec > 59)
-//      throw anna::RuntimeException("Second out of range (0-59) !!", ANNA_FILE_LOCATION);
+  refresh();
 }
 
 
 //------------------------------------------------------------------------------
-//------------------------------------- Date::refresh_regarding_unix_timestamp()
+//---------------------------------------------------- Date::setSystemTimezone()
 //------------------------------------------------------------------------------
-void Date::refresh_regarding_unix_timestamp(void) throw() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "refresh_regarding_unix_timestamp", ANNA_FILE_LOCATION));
-  anna::Guard guard(a_mutex);
-  //anna::Guard<anna::Mutex> guard(a_mutex);
-  _putenv(get_TZ_context().getValue().c_str());
-  struct tm *ptrTm;
-  struct tm resTm;
-  //ptrTm = localtime_r(&a_unix_timestamp, &resTm); NO FUNCIONA BIEN EN LINUX!!
-  ptrTm = localtime(&a_unix_timestamp);
-  // OJO:
-  //   ctime() -> localtime() -> __tz_convert() -> __libc_lock_lock()
-  //   So, glibc does not guarantee the sane behavior when one uses ctime() in
-  //   signal handler.
-  //
-  //   Este problema puede ser de algún bug de la librería libc.so.6 de linux.
-  //   Recomiendan poner LD_ASSUME_KERNEL=2.4.1
-  // Otra solucion sera hacerlo MT-Safe con guardas
-  a_tm_struct = *ptrTm;
-  // Returns begining
-  _putenv(a_local_tz.getValue().c_str());
-  static char cad_aux[32];
-  sprintf(cad_aux, STRING_FORMAT_yyyymmddHHmmss,   1900 + a_tm_struct.tm_year, 1 + (a_tm_struct.tm_mon), a_tm_struct.tm_mday,
-          a_tm_struct.tm_hour, a_tm_struct.tm_min, a_tm_struct.tm_sec);
-  // Assignment:
-  _yyyymmddHHmmss = cad_aux;
+void Date::setSystemTimezone() throw() {
+  a_tz = functions::getSystemTimezone();
+  // Refresh the other data:
+  refresh();
 }
 
-// public
-
-// sets
-
 
 //------------------------------------------------------------------------------
-//----------------------------------------------------------- Date::initialize()
+//---------------------------------------------------------------- Date::store()
 //------------------------------------------------------------------------------
-void Date::initialize(const char * TzContext) throw() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "initialize", ANNA_FILE_LOCATION));
-  _initialize(TzContext);
+void Date::store(const time_t & unixTimestamp) throw() {
+  a_timestamp = unixTimestamp;
+  // Refresh the other data:
+  refresh();
 }
 
 
 //------------------------------------------------------------------------------
-//--------------------------------------------------------- Date::setTzContext()
+//------------------------------------------------------------- Date::storeNtp()
 //------------------------------------------------------------------------------
-void Date::setTzContext(const char * TzContext) throw() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "setTzContext", ANNA_FILE_LOCATION));
-  set_tz_context(TzContext);
+void Date::storeNtp(const unsigned int & ntpTimestamp) throw() {
+  a_timestamp = ntpTimestamp - TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970;
+  // Refresh the other data:
+  refresh();
 }
 
 
-
 //------------------------------------------------------------------------------
 //---------------------------------------------------------------- Date::store()
 //------------------------------------------------------------------------------
-void Date::store(const char* dateTimeAsStringFormat, const std::string & dateTimeAsString, const char * OriginTz)
+void Date::store(const struct tm &date, const char *TZ)
 
 throw(anna::RuntimeException)
 
 {
-  // Get equivalent 'tm':
-  struct tm TmOrigin;
-  memset(&TmOrigin, 0, sizeof(TmOrigin));
-
-  if(strptime(dateTimeAsString.c_str(), dateTimeAsStringFormat, &TmOrigin) == NULL) {
-    std::string msg("Error during strptime() conversion: '");
-    msg += dateTimeAsString;
-    msg += "' can't be interpreted as '";
-    msg += dateTimeAsStringFormat;
-    msg += "'";
-    throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
+  if (TZ) {
+    Timezone aux;
+    aux.set(TZ);
+    aux.apply();
+  }
+  else {
+    functions::getSystemTimezone().apply();
   }
 
-  store(TmOrigin, OriginTz);
-}
-
-
-void Date::store(const std::string & yyyymmddHHmmss, const char * OriginTz)
-
-throw(anna::RuntimeException)
-
-{
-  check_yyyymmddHHmmss(yyyymmddHHmmss);  // launch exception when format error (14 digits)
-  // Could be good, but not assing (perhaps 'strptime' could fail)
-// Limitaciones del 'strptime' usado por 'store(format, cadena)':
-// El formato directamente sacado de este interfaz ("%Y%m%d%H%M%S") no valida las fechas (meses 13, dias 32, etc),
-//  para ello hay que poner separadores en el formato (mucho más robusto). Aun asi, 'strptime' sigue "tragandose cosas"
-//  como por ejemplo segundos=60 (07:54:60 lo convierte a 07:55:00), y no comprueba los años bisiestos (de febrero traga
-//  29 dias siempre, aunque no traga 30)
-// Solucion, convertimos la cadena a otra con separadores para dar mayor robustez (aunque no es perfecto como se ha dicho):
-  int tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec;
-  sscanf(yyyymmddHHmmss.c_str(), STRING_FORMAT_yyyymmddHHmmss, &tm_year, &tm_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec);
-  static char cad_aux[64];
-  sprintf(cad_aux, "%04d-%02d-%02d-%02d-%02d-%02d", tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec);
-  store(STRPTIME_FORMAT_yyyy_mm_dd_HH_mm_ss, cad_aux, OriginTz);
-}
-
-
-//------------------------------------------------------------------------------
-//---------------------------------------------------------------- Date::store()
-//------------------------------------------------------------------------------
-void Date::store(const struct tm & TmOrigen, const char * OriginTz)
-
-throw(anna::RuntimeException)
-
-{
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "store", ANNA_FILE_LOCATION));
-  _putenv(OriginTz);
   // Set '-1' on 'tm_isdst', or it could be an ambiguity on tranformation
   //  returning inexact timestamp. This setting force system to check the correct flag:
-  struct tm TmOrigen_isdst_menos1 = TmOrigen;
-  TmOrigen_isdst_menos1.tm_isdst = -1;
-  time_t unixTimestamp = mktime((struct tm*) & TmOrigen_isdst_menos1);
+  struct tm dateIsdst_1 = date;
+  dateIsdst_1.tm_isdst = -1;
+  time_t unixTimestamp = mktime((struct tm*) & dateIsdst_1);
 
   if(unixTimestamp == (time_t) - 1)
     throw anna::RuntimeException("Error during mktime() conversion !!", ANNA_FILE_LOCATION);
 
-  a_unix_timestamp = unixTimestamp;
+  a_timestamp = unixTimestamp;
+
   // Refresh the othr data:
-  refresh_regarding_unix_timestamp();
+  refresh();
 }
 
 
 //------------------------------------------------------------------------------
 //---------------------------------------------------------------- Date::store()
 //------------------------------------------------------------------------------
-void Date::store(const time_t & unixTimestamp) throw() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "store unix timestamp", ANNA_FILE_LOCATION));
-  a_unix_timestamp = unixTimestamp;
-  // Refresh the other data:
-  refresh_regarding_unix_timestamp();
-}
+void Date::store(const std::string &stringDate, const char *TZ, const char *strptimeFormat)
+throw(anna::RuntimeException)
+{
+  if(strptimeFormat == NULL)
+    throw anna::RuntimeException("Invalid NULL strptimeFormat !!", ANNA_FILE_LOCATION);
 
+  // Get equivalent 'tm':
+  struct tm tmOrigin;
+  memset(&tmOrigin, 0, sizeof(tmOrigin));
 
-//------------------------------------------------------------------------------
-//------------------------------------------------------------- Date::storeNtp()
-//------------------------------------------------------------------------------
-void Date::storeNtp(const unsigned int & ntpTimestamp) throw() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "store ntp timestamp", ANNA_FILE_LOCATION));
-  a_unix_timestamp = ntpTimestamp - TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970;
-  // Refresh the other data:
-  refresh_regarding_unix_timestamp();
+  if(strptime(stringDate.c_str(), strptimeFormat, &tmOrigin) == NULL) {
+    std::string msg("Error during strptime() conversion: '");
+    msg += stringDate;
+    msg += "' can't be interpreted as '";
+    msg += strptimeFormat;
+    msg += "'";
+    throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
+  }
+
+  store(tmOrigin, TZ);
 }
 
 
@@ -373,65 +207,38 @@ void Date::storeNtp(const unsigned int & ntpTimestamp) throw() {
 //-------------------------------------------------------------- Date::operator=
 //------------------------------------------------------------------------------
 Date & Date::operator = (const Date & d) {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "operator=", ANNA_FILE_LOCATION));
   // avoid itself copy: i.e., Date a,b; a=&b; a=b; b=a;
   if(this == &d) return (*this);
 
-  a_TZ_context = d.get_TZ_context();
-  a_unix_timestamp = d.getUnixTimestamp();
-  a_tm_struct = d.getTm();
-  _yyyymmddHHmmss = d.yyyymmddHHmmss();
+  a_timestamp = d.getUnixTimestamp();
+  a_tz.set(d.getTz());
+  a_tm = d.getTm();
   return (*this);
 }
 
 
 // gets
 
-//------------------------------------------------------------------------------
-//--------------------------------------------------------- Date::getTzContext()
-//------------------------------------------------------------------------------
-const std::string & Date::getTzContext(void) const throw() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "getTzContext", ANNA_FILE_LOCATION));
-  return (a_TZ_context.getValue());
-}
-
-
-//------------------------------------------------------------------------------
-//------------------------------------------------------- Date::yyyymmddHHmmss()
-//------------------------------------------------------------------------------
-const std::string & Date::yyyymmddHHmmss(void) const throw() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "yyyymmddHHmmss", ANNA_FILE_LOCATION));
-  return (_yyyymmddHHmmss);
-}
-
 
 //------------------------------------------------------------------------------
-//----------------------------------------------------- Date::getUnixTimestamp()
+//--------------------------------------------------------------- Date::getDay()
 //------------------------------------------------------------------------------
-const time_t & Date::getUnixTimestamp(void) const throw() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "getUnixTimestamp", ANNA_FILE_LOCATION));
-  return (a_unix_timestamp);
-}
+const char *Date::getDay(void) const throw() {
 
+  static const char *weekdayname[] = {"Sunday", "Monday", "Tuesday",
+    "Wednesday", "Thursday", "Friday", "Saturday"};
 
-//------------------------------------------------------------------------------
-//------------------------------------------------------ Date::getNtpTimestamp()
-//------------------------------------------------------------------------------
-unsigned int Date::getNtpTimestamp(void) const throw() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "getNtpTimestamp", ANNA_FILE_LOCATION));
-  unsigned int ntp_timestamp = a_unix_timestamp + TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970;
-  return (ntp_timestamp);
+  return weekdayname[a_tm.tm_wday];
 }
 
 
 //------------------------------------------------------------------------------
-//---------------------------------------------------------------- Date::getTm()
+//------------------------------------------------------- Date::yyyymmddHHmmss()
 //------------------------------------------------------------------------------
-const struct tm & Date::getTm(void) const throw() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "getTm", ANNA_FILE_LOCATION));
-
-
-  return (a_tm_struct);
+std::string Date::yyyymmddHHmmss(void) const throw() {
+  return anna::functions::asString("%04d%02d%02d%02d%02d%02d",
+     1900 + a_tm.tm_year, 1 + (a_tm.tm_mon), a_tm.tm_mday,
+     a_tm.tm_hour, a_tm.tm_min, a_tm.tm_sec);
 }
 
 
@@ -439,34 +246,16 @@ const struct tm & Date::getTm(void) const throw() {
 //------------------------------------------------------------- Date::asString()
 //------------------------------------------------------------------------------
 std::string Date::asString(void) const throw() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "asString", ANNA_FILE_LOCATION));
-  std::string trace;
-  static char cad_aux[256];
-  //bool differentContextAndLocalTZ = getTzContext() != a_local_tz.getValue();
-  sprintf(cad_aux, "%02d/%02d/%04d %02d:%02d:%02d",
-          //          yyyymmddHHmmss().c_str(),
-          getTm().tm_mday, 1 + (getTm().tm_mon), 1900 + getTm().tm_year,
-          getTm().tm_hour, getTm().tm_min, getTm().tm_sec);
-  trace = cad_aux;
-
-//   if (!(get_TZ_context().isUnset()))
-//      if (!(get_TZ_context().isEmpty()))
-//         { trace += " "; trace += get_TZ_context().getValue(); }
-  if(getTzContext() != ""/* && differentContextAndLocalTZ*/) { trace += " "; trace += getTzContext(); }
-
-  sprintf(cad_aux, ", isdst = %d [Unix Timestamp: %ld, Ntp Timestamp: %u]", getTm().tm_isdst, getUnixTimestamp(), getNtpTimestamp());
-  trace += cad_aux;
-
-//   if (!(a_local_tz.isUnset()))
-//      if (!(a_local_tz.isEmpty()))
-//         { trace += ", Local TZ = "; trace += a_local_tz.getValue(); }
-  if(a_local_tz.getValue() != "") {
-    //trace += differentContextAndLocalTZ ? ", Local TZ = ":", TZ Context = Local TZ = ";
-    trace += ", Local TZ = ";
-    trace += a_local_tz.getValue();
-  }
 
-  return (trace);
+  std::string result = anna::functions::asString("%s %02d/%02d/%04d %02d:%02d:%02d ", getDay(),
+                          getTm().tm_mday, 1 + (getTm().tm_mon), 1900 + getTm().tm_year,
+                          getTm().tm_hour, getTm().tm_min, getTm().tm_sec);
+  result += getTzAsString();
+  result += anna::functions::asString(", isdst = %d [Unix Timestamp: %ld, Ntp Timestamp: %u]", getTm().tm_isdst, getUnixTimestamp(), getNtpTimestamp());
+  result += ", System Timezone: ";
+  result += functions::getSystemTimezone().asString();
+
+  return result;
 }
 
 
@@ -474,21 +263,15 @@ std::string Date::asString(void) const throw() {
 //---------------------------------------------------------------- Date::asXML()
 //------------------------------------------------------------------------------
 anna::xml::Node* Date::asXML(anna::xml::Node* parent) const throw() {
-  //LOGMETHOD (TraceMethod tm ("anna::time::Date", "asXML", ANNA_FILE_LOCATION));
   //anna::xml::Node* result = parent->createChild("anna.time.Date");
-  //bool differentContextAndLocalTZ = getTzContext() != a_local_tz.getValue();
   parent->createAttribute("Date", anna::functions::asString("%02d/%02d/%04d", getTm().tm_mday, 1 + (getTm().tm_mon), 1900 + getTm().tm_year));
+  parent->createAttribute("Day", getDay());
   parent->createAttribute("Time", anna::functions::asString("%02d:%02d:%02d", getTm().tm_hour, getTm().tm_min, getTm().tm_sec));
-
-  if(getTzContext() != ""/* && differentContextAndLocalTZ*/) parent->createAttribute("TZContext", getTzContext());
-
+  parent->createAttribute("TZ", getTzAsString());
   parent->createAttribute("Isdst", (getTm().tm_isdst) ? "yes" : "no");
-//   parent->createAttribute("UnixTimestamp", anna::functions::asString("%lu seconds", getUnixTimestamp())); // unsigned long -> %lu
-//   parent->createAttribute("NtpTimestamp", anna::functions::asString("%u seconds", getNtpTimestamp())); // unsigned int -> %u
   parent->createAttribute("UnixTimestamp", anna::functions::asString((const int)getUnixTimestamp()));
   parent->createAttribute("NtpTimestamp", anna::functions::asString(getNtpTimestamp()));
-
-  if(a_local_tz.getValue() != "") parent->createAttribute(/*differentContextAndLocalTZ ? "LocalTZ":"TZContext=LocalTZ"*/"LocalTZ", a_local_tz.getValue());
+  parent->createAttribute("SystemTimezone", functions::getSystemTimezone().asString());
 
   return parent;
 }
index b044fd2..e3ef33d 100644 (file)
@@ -36,7 +36,7 @@
 
 // Local
 #include <anna/time/functions.hpp>
-#include <anna/time/internal/TZ.hpp>
+#include <anna/time/internal/Timezone.hpp>
 
 // Standard
 #include <stdlib.h> // getenv
 
 namespace anna {
 namespace time {
-TZ shell_local_tz;
+Timezone SystemTimezone;
 unsigned long long int SecondsReference;
 }
 }
 
 
 void anna::time::functions::initialize() throw() {
-//throw(anna::RuntimeException) {
-// If the system is configured properly, the default time zone will be correct. You might set TZ if you are
-//  using a computer over a network from a different time zone, and would like times reported to you in the
-//  time zone local to you, rather than what is local to the computer.
   static bool cached = false;
-
   if(!cached) {
-    // The getenv() function need not be reentrant. A function that is not required to be reentrant is not
-    //  required to be thread-safe.
-    const char *local_tz = getenv("TZ");
-    shell_local_tz.set(local_tz);
-//      if (shell_local_tz.isUnset())
-//         std::cout << "'TZ' enviroment variable is not defined on shell (it shouldn't be necesary)" << std::endl;
-//    setControlPoint();
+    SystemTimezone.set(getenv("TZ"));
     SecondsReference = 0;
     cached = true;
   }
@@ -83,12 +72,12 @@ unsigned long long int anna::time::functions::getSecondsReference() throw() {
   return SecondsReference;
 }
 
-const anna::time::TZ & anna::time::functions::getLocalTz(void) throw() {
-  return (shell_local_tz);
+const anna::time::Timezone & anna::time::functions::getSystemTimezone(void) throw() {
+  return (SystemTimezone);
 }
 
 bool anna::time::functions::initialized(void) throw() {
-  return (shell_local_tz.isInitialized());
+  return (SystemTimezone.isInitialized());
 }
 
 unsigned long long int anna::time::functions::unixSeconds(void) throw() {
index 3820199..b8ddcc0 100644 (file)
@@ -51,10 +51,9 @@ using namespace anna;
 //     http://www.boost.org/doc/libs/1_44_0/libs/test/doc/html/utf/testing-tools/reference.html
 
 BOOST_AUTO_TEST_CASE(date) {
-  const char * tzarg = NULL;
   anna::time::functions::initialize();
   anna::time::Date current, current2;
-  current.setCurrent();
+  current.setNow();
   unsigned int ntptime = current.getNtpTimestamp();
   time_t unixtime = current.getUnixTimestamp();
   current2.storeNtp(ntptime);
@@ -62,26 +61,33 @@ BOOST_AUTO_TEST_CASE(date) {
   current2.storeUnix(unixtime);
   std::string unixStr = current2.asString();
   BOOST_REQUIRE_EQUAL(ntpStr, unixStr);
+
   anna::time::Date myBirth("CET"); // 19 December 1974, 10:00 (GMT+1 = UTC + 1 = CET)
-  //anna::time::Date myBirth; // if Context TZ = shell TZ = "CET"
   myBirth.store("19741219101500"); // yyyymmddHHmmss
   anna::time::Date same_moment_canary_island("GMT");
   same_moment_canary_island.store(myBirth.getUnixTimestamp());
-  myBirth.setTzContext("GMT");
+  myBirth.setTz("GMT");
   BOOST_REQUIRE_EQUAL(same_moment_canary_island.yyyymmddHHmmss(), myBirth.yyyymmddHHmmss());
+
   anna::time::Date birthday("EET");
   birthday.store(same_moment_canary_island.getTm(), "GMT");  // TZ origin = "GMT"
-  //BOOST_REQUIRE_EQUAL(birthday, myBirth);
   BOOST_REQUIRE_EQUAL(birthday.getUnixTimestamp(), myBirth.getUnixTimestamp());
-  myBirth.setTzContext(anna::time::functions::getLocalTz().getValue().c_str());
-  birthday.setTzContext(anna::time::functions::getLocalTz().getValue().c_str());  // Go from "EET" to "CET"
-  // TODO: review the following test case:
-  //BOOST_REQUIRE_EQUAL(myBirth.yyyymmddHHmmss(), birthday.yyyymmddHHmmss());
+
+  myBirth.setTz();
+  birthday.setTz();
+  BOOST_REQUIRE_EQUAL(myBirth.asString(), birthday.asString());
+  BOOST_REQUIRE_EQUAL(myBirth.yyyymmddHHmmss(), birthday.yyyymmddHHmmss());
+
+  myBirth.setTz("GMT");
+  BOOST_REQUIRE_EQUAL(myBirth.yyyymmddHHmmss(), "19741219091500");
+
   // Adding 18 years to 'myBirth':
+  same_moment_canary_island.setTz("CET");
+  anna::time::Date eighteen("CET");
   struct tm Tm = myBirth.getTm();
   Tm.tm_year += 18;
-  anna::time::Date eighteen("CET");
-  eighteen.store(Tm);
+  eighteen.store(Tm, "GMT");
   BOOST_REQUIRE(eighteen >= same_moment_canary_island);
+  BOOST_REQUIRE_EQUAL(eighteen.yyyymmddHHmmss(), "19921219101500");
 }