00001
00002
00003 #include <ctime>
00004 #include <cstdlib>
00005 #include <cstdio>
00006 #include <cmath>
00007 #include "facilities/Timestamp.h"
00008
00009 namespace facilities {
00010 const double Timestamp::julian1970 = 2440587.5;
00011 const int Timestamp::secPerDay = (24*60*60);
00012 const double Timestamp::inverseNano = 1000 * 1000 * 1000;
00013 const int Timestamp::inverseNanoInt = 1000 * 1000 * 1000;
00014 const long int Timestamp::maxInt = 0x7fffffff;
00015
00016 Timestamp::TZOffset Timestamp::s_tz;
00017
00018
00019 Timestamp::Timestamp() : m_nano(0) {
00020 m_time = time(0);
00021 }
00022
00023
00024
00025
00026
00027
00028 Timestamp::Timestamp(long int seconds, int nano, int tzOffset)
00029 : m_time((time_t) seconds), m_nano(nano)
00030 {
00031 if ((nano >= inverseNanoInt) || (nano < 0) || (seconds < 0))
00032 throw BadTimeInput("facilities::Timestamp bad nano argument");
00033 seconds += tzOffset;
00034 }
00035
00036
00037 Timestamp::Timestamp(double julian) {
00038 double secs;
00039 secs = (julian - julian1970) * secPerDay;
00040
00041 if ((fabs(secs) > maxInt) || (secs < 0) )
00042 throw BadTimeInput("Julian time not in range [1970, 2037]");
00043
00044 m_time = (long int) secs;
00045
00046
00047
00048 if (m_time > secs) m_time--;
00049 m_nano = (int) ((secs - m_time)/inverseNano);
00050 }
00051
00052
00053 Timestamp::Timestamp(const std::string& str, int tzOffset) : m_nano(0) {
00054 m_time = toBinary(str);
00055 m_time += tzOffset;
00056 }
00057
00058
00059 Timestamp::Timestamp(int year, int month,
00060 int day, int hour,
00061 int minute, int second,
00062 int nano) : m_nano(nano) {
00063 struct tm fields;
00064
00065
00066
00067
00068 if ((month < 1 ) || (month > 12) || (day < 1) || (day > 31) ||
00069 (hour < 0) || (hour > 23) ||
00070 (minute < 0) || (minute > 59) ||
00071 (second < 0 ) || (second >= 60) ||
00072 (year < 1970) || (year > 2037) ||
00073 (nano < 0 ) || (nano >= inverseNanoInt) )
00074 throw BadTimeInput("facilities::Timestamp Bad subfield");
00075
00076 fields.tm_year = year - 1900;
00077 fields.tm_mon = month - 1;
00078 fields.tm_mday = day;
00079 fields.tm_hour = hour;
00080 fields.tm_min = minute;
00081 fields.tm_sec = (long int) second;
00082 fields.tm_wday = -1;
00083 fields.tm_yday = -1;
00084
00085
00086 fields.tm_isdst = 0;
00087
00088
00089 m_time = mktime(&fields) - Timestamp::s_tz.m_tzseconds;
00090 }
00091
00092 std::string Timestamp::getString() const {
00093 std::string str;
00094
00095 toString(m_time, str);
00096 return str;
00097 }
00098
00099 double Timestamp::getJulian() const {
00100 double julian = (m_time + m_nano/inverseNano)/secPerDay;
00101 julian += julian1970;
00102 return julian;
00103 }
00104
00105
00106 time_t Timestamp::toBinary(const std::string& strTime) {
00107
00108 struct tm fields;
00109
00110 unsigned int pos;
00111 unsigned int oldPos = 0;
00112
00113
00114
00115 char delim = '-';
00116
00117 pos = strTime.find(delim, oldPos);
00118
00119
00120 if (pos >= strTime.size()) return 0;
00121
00122 fields.tm_year = atoi((strTime.substr(oldPos, pos)).c_str()) - 1900;
00123 if ((fields.tm_year < 70) || (fields.tm_year > 137))
00124 throw BadTimeInput("facilities::Timestamp bad year");
00125 oldPos = pos + 1;
00126 pos = strTime.find(delim, oldPos);
00127
00128
00129 if (pos >= strTime.size())
00130 throw BadTimeInput("Bad string format for facilities::Timestamp");
00131
00132 fields.tm_mon = atoi((strTime.substr(oldPos, pos)).c_str()) - 1;
00133 if ((fields.tm_mon < 0) || (fields.tm_mon > 11))
00134 throw BadTimeInput("facilities::Timestamp bad month");
00135
00136
00137 oldPos = pos + 1;
00138
00139
00140 delim = ' ';
00141 pos = strTime.find(delim, oldPos);
00142
00143 fields.tm_mday = atoi((strTime.substr(oldPos, pos)).c_str());
00144
00145 if ((fields.tm_mday < 1) || (fields.tm_mday > 31))
00146 throw BadTimeInput("facilities::Timestamp bad day of month");
00147
00148
00149 fields.tm_hour = fields.tm_min = fields.tm_sec = 0;
00150
00151 if (pos < strTime.size() ) {
00152 delim = ':';
00153 oldPos = pos + 1;
00154
00155 pos = strTime.find(delim, oldPos);
00156
00157 fields.tm_hour = atoi((strTime.substr(oldPos, pos)).c_str());
00158 if ((fields.tm_hour > 23) || (fields.tm_hour < 0))
00159 throw BadTimeInput("facilities::Timestamp bad hour");
00160
00161
00162 if (pos < strTime.size() ) {
00163 oldPos = pos + 1;
00164 pos = strTime.find(delim, oldPos);
00165 fields.tm_min = atoi((strTime.substr(oldPos, pos)).c_str());
00166 if ((fields.tm_min > 59) || (fields.tm_hour < 0))
00167 throw BadTimeInput("facilities::Timestamp bad minutes");
00168
00169 if (pos < strTime.size() ) {
00170 oldPos = pos + 1;
00171 pos = strTime.find(delim, oldPos);
00172 fields.tm_sec = atoi((strTime.substr(oldPos, pos)).c_str());
00173 if ((fields.tm_sec > 59) || (fields.tm_hour < 0))
00174 throw BadTimeInput("facilities::Timestamp bad seconds");
00175 }
00176 }
00177 }
00178
00179 fields.tm_wday = -1;
00180 fields.tm_yday = -1;
00181 fields.tm_isdst = 0;
00182 return mktime(&fields) - Timestamp::s_tz.m_tzseconds;
00183 }
00184
00185 void Timestamp::toString(time_t bin, std::string& strTime) {
00186 struct tm * fields = gmtime(&bin);
00187
00188 strTime.resize(0);
00189
00190 char buf[20];
00191 char* bufPtr = &buf[0];
00192 sprintf(buf, "%i", fields->tm_year + 1900);
00193 strTime += bufPtr; strTime += "-";
00194 sprintf(buf, "%02i", fields->tm_mon +1);
00195 strTime += bufPtr; strTime += "-";
00196 sprintf(buf, "%02i", fields->tm_mday);
00197 strTime += bufPtr; strTime += " ";
00198 sprintf(buf, "%02i", fields->tm_hour);
00199 strTime += bufPtr; strTime += ":";
00200 sprintf(buf, "%02i", fields->tm_min);
00201 strTime += bufPtr; strTime += ":";
00202 sprintf(buf, "%02i", fields->tm_sec);
00203 strTime += bufPtr;
00204 }
00205
00206
00207 Timestamp::TZOffset::TZOffset() {
00208 struct tm fields;
00209
00210
00211 fields.tm_year = 70;
00212 fields.tm_mon = 0;
00213 fields.tm_mday = 1;
00214 fields.tm_hour = 12;
00215 fields.tm_min = 0;
00216 fields.tm_sec = 0;
00217 fields.tm_isdst = 0;
00218
00219 m_tzseconds = mktime(&fields) - 12*60*60;
00220 m_isDst = fields.tm_isdst;
00221 }
00222 }
00223
00224
00225
00226
00227
00228