在Poco库中,与时间和日期相关的一些类,其内部实现是非常简单的。看相关文档时,比较有意思的倒是历史上的不同时间表示法。
首先这些时间结构体的精度不同,Second(time_t/tm), microsecond(timeval/SYSTEMTIME), 100nanoSeconds(FILETIME),nanoSeconds(timespec)。还有一些结构和操作系统相关,如clock_t,windows下为1毫秒,POSIX 下为1微秒,对应clock_t,不同平台的差异,可以用宏CLOCKS_PER_SEC解决。
起始时间不同,time_t起始于1970年1月1日0时0分0秒,tm表示起始于1900年,SYSTEMTIME/FILETIME起始于1601年,clock起始于机器开机。
上面各个时间的定义如下:
typedef struct _FILETIME { DWORD dwLowDateTime; DWORD dwHighDateTime; } FILETIME, *PFILETIME; typedef struct _SYSTEMTIME { WORD wYear; WORD wMonth; WORD wDayOfWeek; WORD wDay; WORD wHour; WORD wMinute; WORD wSecond; WORD wMilliseconds; // 毫秒 } SYSTEMTIME, *PSYSTEMTIME; struct tm { int tm_sec; /* 秒 – 取值区间为[0,59] */ int tm_min; /* 分 - 取值区间为[0,59] */ int tm_hour; /* 时 - 取值区间为[0,23] */ int tm_mday; /* 一个月中的日期 - 取值区间为[1,31] */ int tm_mon; /* 月份(从一月开始,0代表一月) - 取值区间为[0,11] */ int tm_year; /* 年份,其值等于实际年份减去1900 */ int tm_wday; /* 星期 – 取值区间为[0,6],其中0代表星期天,1代表星期一,以此类推 */ int tm_yday; /* 从每年的1月1日开始的天数 – 取值区间为[0,365],其中0代表1月1日,1代表1月2日,以此类推 */ int tm_isdst; /* 夏令时标识符,实行夏令时的时候,tm_isdst为正。不实行夏令时的进候,tm_isdst为0;不了解情况时,tm_isdst()为负。*/ }; typedef __time64_t time_t; // 秒 struct timeval { long tv_sec; /* seconds */ long tv_usec; /* and microseconds 毫秒*/ }; struct timespec { __time_t tv_sec; /*seconds 秒*/ long int tv_nsec; /*nanoseconds 纳秒*/ } typedef unsigned long clock_t; // 毫秒
同这些数据结构相关联,C语言为tm,time_t提供了一组函数用于时间运算和数据结构转换:
// 日历时间(一个用time_t表示的整数) // 比较日历时间 double difftime(time_t time1, time_t time0); // 获取日历时间 time_t time(time_t * timer); // 转换日历时间为字符串 char * ctime(const time_t *timer); // 转换日历时间为我们平时看到的把年月日时分秒分开显示的时间格式tm(GMT timezone) struct tm * gmtime(const time_t *timer); // 转换日历时间为我们平时看到的把年月日时分秒分开显示的时间格式tm(本地 timezone) struct tm * localtime(const time_t * timer); // 关于本地时间的计算公式: localtime = utctime[Gmt time] + utcOffset()[时区偏移] + dst()[夏令时偏移] // 把tm转换为字符串 char * asctime(const struct tm * timeptr); // 把tm转换为日历时间 time_t mktime(struct tm * timeptr); // 获取开机以来的微秒数 clock_t clock (void);
Windows下特有的时间转换函数包括:
GetLocalTime能够得到本地电脑设置时区的时间,得到的类型是SYSTEMTIME的类型。
void GetSystemTime(LPSYSTEMTIME lpSystemTime); // GetSystemTime函数获得当前的UTC时间 void GetLocalTime(LPSYSTEMTIME lpSystemTime); // GetLocalTime获得当前的本地时间 BOOL SystemTimeToFileTime(const SYSTEMTIME* lpSystemTime, LPFILETIME lpFileTime); BOOL FileTimeToSystemTime(const FILETIME* lpFileTime, LPSYSTEMTIME lpSystemTime); BOOL LocalFileTimeToFileTime(const FILETIME* lpLocalFileTime, LPFILETIME lpFileTime); BOOL FileTimeToLocalFileTime(const FILETIME* lpFileTime, LPFILETIME lpLocalFileTime);
Windows下特有的获取时间精度的函数包括(精度微秒):
BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency); BOOL QueryPerformanceCounter(LARGE_INTEGER *lpCount);
class Foundation_API Timestamp { public: typedef Int64 TimeVal; /// monotonic UTC time value in microsecond resolution typedef Int64 UtcTimeVal; /// monotonic UTC time value in 100 nanosecond resolution typedef Int64 TimeDiff; /// difference between two timestamps in microseconds Timestamp(); /// Creates a timestamp with the current time. Timestamp(TimeVal tv); /// Creates a timestamp from the given time value. Timestamp(const Timestamp& other); /// Copy constructor. ~Timestamp(); /// Destroys the timestamp Timestamp& operator = (const Timestamp& other); Timestamp& operator = (TimeVal tv); void swap(Timestamp& timestamp); /// Swaps the Timestamp with another one. void update(); /// Updates the Timestamp with the current time. bool operator == (const Timestamp& ts) const; bool operator != (const Timestamp& ts) const; bool operator > (const Timestamp& ts) const; bool operator >= (const Timestamp& ts) const; bool operator < (const Timestamp& ts) const; bool operator <= (const Timestamp& ts) const; Timestamp operator + (TimeDiff d) const; Timestamp operator - (TimeDiff d) const; TimeDiff operator - (const Timestamp& ts) const; Timestamp& operator += (TimeDiff d); Timestamp& operator -= (TimeDiff d); std::time_t epochTime() const; /// Returns the timestamp expressed in time_t. /// time_t base time is midnight, January 1, 1970. /// Resolution is one second. UtcTimeVal utcTime() const; /// Returns the timestamp expressed in UTC-based /// time. UTC base time is midnight, October 15, 1582. /// Resolution is 100 nanoseconds. TimeVal epochMicroseconds() const; /// Returns the timestamp expressed in microseconds /// since the Unix epoch, midnight, January 1, 1970. TimeDiff elapsed() const; /// Returns the time elapsed since the time denoted by /// the timestamp. Equivalent to Timestamp() - *this. bool isElapsed(TimeDiff interval) const; /// Returns true iff the given interval has passed /// since the time denoted by the timestamp. static Timestamp fromEpochTime(std::time_t t); /// Creates a timestamp from a std::time_t. static Timestamp fromUtcTime(UtcTimeVal val); /// Creates a timestamp from a UTC time value. static TimeVal resolution(); /// Returns the resolution in units per second. /// Since the timestamp has microsecond resolution, /// the returned value is always 1000000. private: TimeVal _ts; };
Timestamp的成员函数:
1. time_t epochTime() const
返回一个以epoch time计算的日历时间(精度秒)。(函数内部会把基于UTC时间的值转为基于epoch time的值)
2. UtcTimeVal utcTime() const
返回一个以UTC时间计算的日历时间(精度100纳秒)。
3. TimeVal epochMicroseconds() const
返回一个以epoch time计算的日历时间(精度微秒)
4. void update()
取当前的时间更新
5. TimeDiff elapsed() const
返回当前时间与Timestamp内部时间_ts的一个时间差值(精度微秒)
6. bool isElapsed(TimeDiff interval) const
如果当前时间与Timestamp内部时间_ts的一个时间差值大于interval时间,返回true。(精度微秒)
Timestamp算术计算:
1. Timestamp operator + (TimeDiff diff) const
增加一个时间偏移,并返回值。(精度微秒)
2. Timestamp operator - (TimeDiff diff) const
减掉一个时间偏移,并返回值。(精度微秒)
3. TimeDiff operator - (const Timestamp& ts) const
返回两个Timestamp对象的时间偏移。(精度微秒)
4. Timestamp& operator += (TimeDiff d)
Timestamp& operator -= (TimeDiff d)
增加或减小一个时间偏移值
下面来看一个例子:
#include "Poco/Timestamp.h" #include <ctime> using Poco::Timestamp; int main(int argc, char** argv) { Timestamp now; // the current date and time std::time_t t1 = now.epochTime(); // convert to time_t ... Timestamp ts1(Timestamp::fromEpochTime(t1)); // ... and back again for (int i = 0; i < 100000; ++i) ; // wait a bit Timestamp::TimeDiff diff = now.elapsed(); // how long did it take? Timestamp start(now); // save start time now.update(); // update with current time diff = now - start; // again, how long? return 0; }
class Foundation_API DateTime { public: enum Months /// Symbolic names for month numbers (1 to 12). { JANUARY = 1, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER }; enum DaysOfWeek /// Symbolic names for week day numbers (0 to 6). { SUNDAY = 0, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY }; DateTime(); /// Creates a DateTime for the current date and time. DateTime(const Timestamp& timestamp); /// Creates a DateTime for the date and time given in /// a Timestamp. DateTime(int year, int month, int day, int hour = 0, int minute = 0, int second = 0, int millisecond = 0, int microsecond = 0); /// Creates a DateTime for the given Gregorian date and time. /// * year is from 0 to 9999. /// * month is from 1 to 12. /// * day is from 1 to 31. /// * hour is from 0 to 23. /// * minute is from 0 to 59. /// * second is from 0 to 59. /// * millisecond is from 0 to 999. /// * microsecond is from 0 to 999. DateTime(double julianDay); /// Creates a DateTime for the given Julian day. DateTime(Timestamp::UtcTimeVal utcTime, Timestamp::TimeDiff diff); /// Creates a DateTime from an UtcTimeVal and a TimeDiff. /// /// Mainly used internally by DateTime and friends. DateTime(const DateTime& dateTime); /// Copy constructor. Creates the DateTime from another one. ~DateTime(); /// Destroys the DateTime. DateTime& operator = (const DateTime& dateTime); /// Assigns another DateTime. DateTime& operator = (const Timestamp& timestamp); /// Assigns a Timestamp. DateTime& operator = (double julianDay); /// Assigns a Julian day. DateTime& assign(int year, int month, int day, int hour = 0, int minute = 0, int second = 0, int millisecond = 0, int microseconds = 0); /// Assigns a Gregorian date and time. /// * year is from 0 to 9999. /// * month is from 1 to 12. /// * day is from 1 to 31. /// * hour is from 0 to 23. /// * minute is from 0 to 59. /// * second is from 0 to 59. /// * millisecond is from 0 to 999. /// * microsecond is from 0 to 999. void swap(DateTime& dateTime); /// Swaps the DateTime with another one. int year() const; /// Returns the year. int month() const; /// Returns the month (1 to 12). int week(int firstDayOfWeek = MONDAY) const; /// Returns the week number within the year. /// FirstDayOfWeek should be either SUNDAY (0) or MONDAY (1). /// The returned week number will be from 0 to 53. Week number 1 is the week /// containing January 4. This is in accordance to ISO 8601. /// /// The following example assumes that firstDayOfWeek is MONDAY. For 2005, which started /// on a Saturday, week 1 will be the week starting on Monday, January 3. /// January 1 and 2 will fall within week 0 (or the last week of the previous year). /// /// For 2007, which starts on a Monday, week 1 will be the week startung on Monday, January 1. /// There will be no week 0 in 2007. int day() const; /// Returns the day witin the month (1 to 31). int dayOfWeek() const; /// Returns the weekday (0 to 6, where /// 0 = Sunday, 1 = Monday, ..., 6 = Saturday). int dayOfYear() const; /// Returns the number of the day in the year. /// January 1 is 1, February 1 is 32, etc. int hour() const; /// Returns the hour (0 to 23). int hourAMPM() const; /// Returns the hour (0 to 12). bool isAM() const; /// Returns true if hour < 12; bool isPM() const; /// Returns true if hour >= 12. int minute() const; /// Returns the minute (0 to 59). int second() const; /// Returns the second (0 to 59). int millisecond() const; /// Returns the millisecond (0 to 999) int microsecond() const; /// Returns the microsecond (0 to 999) double julianDay() const; /// Returns the julian day for the date and time. Timestamp timestamp() const; /// Returns the date and time expressed as a Timestamp. Timestamp::UtcTimeVal utcTime() const; /// Returns the date and time expressed in UTC-based /// time. UTC base time is midnight, October 15, 1582. /// Resolution is 100 nanoseconds. bool operator == (const DateTime& dateTime) const; bool operator != (const DateTime& dateTime) const; bool operator < (const DateTime& dateTime) const; bool operator <= (const DateTime& dateTime) const; bool operator > (const DateTime& dateTime) const; bool operator >= (const DateTime& dateTime) const; DateTime operator + (const Timespan& span) const; DateTime operator - (const Timespan& span) const; Timespan operator - (const DateTime& dateTime) const; DateTime& operator += (const Timespan& span); DateTime& operator -= (const Timespan& span); void makeUTC(int tzd); /// Converts a local time into UTC, by applying the given time zone differential. void makeLocal(int tzd); /// Converts a UTC time into a local time, by applying the given time zone differential. static bool isLeapYear(int year); /// Returns true if the given year is a leap year; /// false otherwise. static int daysOfMonth(int year, int month); /// Returns the number of days in the given month /// and year. Month is from 1 to 12. static bool isValid(int year, int month, int day, int hour = 0, int minute = 0, int second = 0, int millisecond = 0, int microsecond = 0); /// Checks if the given date and time is valid /// (all arguments are within a proper range). /// /// Returns true if all arguments are valid, false otherwise. protected: // ... private: // ... Timestamp::UtcTimeVal _utcTime; short _year; short _month; short _day; short _hour; short _minute; short _second; short _millisecond; short _microsecond; };
#include "Poco/DateTime.h" using Poco::DateTime; int main(int argc, char** argv) { DateTime now; // the current date and time in UTC int year = now.year(); int month = now.month(); int day = now.day(); int dow = now.dayOfWeek(); int doy = now.dayOfYear(); int hour = now.hour(); int hour12 = now.hourAMPM(); int min = now.minute(); int sec = now.second(); int ms = now.millisecond(); int us = now.microsecond(); double jd = now.julianDay(); Poco::Timestamp ts = now.timestamp(); DateTime xmas(2006, 12, 25); // 2006-12-25 00:00:00 Poco::Timespan timeToXmas = xmas - now; DateTime dt(1973, 9, 12, 2, 30, 45); // 1973-09-12 02:30:45 dt.assign(2006, 10, 13, 13, 45, 12, 345); // 2006-10-13 12:45:12.345 bool isAM = dt.isAM(); // false bool isPM = dt.isPM(); // true bool isLeap = DateTime::isLeapYear(2006); // false int days = DateTime::daysOfMonth(2006, 2); // 28 bool isValid = DateTime::isValid(2006, 02, 29); // false dt.assign(2006, DateTime::OCTOBER, 22); // 2006-10-22 00:00:00 if (dt.dayOfWeek() == DateTime::SUNDAY) { // ... } return 0; }
#include "Poco/LocalDateTime.h" using Poco::LocalDateTime; int main(int argc, char** argv) { LocalDateTime now; // the current date and local time int year = now.year(); int month = now.month(); int day = now.day(); int dow = now.dayOfWeek(); int doy = now.dayOfYear(); int hour = now.hour(); int hour12 = now.hourAMPM(); int min = now.minute(); int sec = now.second(); int ms = now.millisecond(); int us = now.microsecond(); int tzd = now.tzd(); double jd = now.julianDay(); Poco::Timestamp ts = now.timestamp(); LocalDateTime dt1(1973, 9, 12, 2, 30, 45); // 1973-09-12 02:30:45 dt1.assign(2006, 10, 13, 13, 45, 12, 345); // 2006-10-13 12:45:12.345 LocalDateTime dt2(3600, 1973, 9, 12, 2, 30, 45, 0, 0); // UTC +1 hour dt2.assign(3600, 2006, 10, 13, 13, 45, 12, 345, 0); Poco::Timestamp nowTS; LocalDateTime dt3(3600, nowTS); // construct from Timestamp return 0; }
#include "Poco/Timespan.h" using Poco::Timespan; int main(int argc, char** argv) { Timespan ts1(1, 11, 45, 22, 123433); // 1d 11h 45m 22.123433s Timespan ts2(33*Timespan::SECONDS); // 33s Timespan ts3(2*Timespan::DAYS + 33*Timespan::HOURS); // 3d 33h int days = ts1.days(); // 1 int hours = ts1.hours(); // 11 int totalHours = ts1.totalHours(); // 35 int minutes = ts1.minutes(); // 45 int totalMins = ts1.totalMinutes(); // 2145 int seconds = ts1.seconds(); // 22 int totalSecs = ts1.totalSeconds(); // 128722 return 0; }
#include "Poco/DateTime.h" #include "Poco/Timespan.h" using Poco::DateTime; using Poco::Timespan; int main(int argc, char** argv) { // what is my age? DateTime birthdate(1973, 9, 12, 2, 30); // 1973-09-12 02:30:00 DateTime now; Timespan age = now - birthdate; int days = age.days(); // in days int hours = age.totalHours(); // in hours int secs = age.totalSeconds(); // in seconds // when was I 10000 days old? Timespan span(10000*Timespan::DAYS); DateTime dt = birthdate + span; return 0; }
#include "Poco/Timezone.h" #include "Poco/Timestamp.h" using Poco::Timezone; using Poco::Timestamp; int main(int argc, char** argv) { int utcOffset = Timezone::utcOffset(); int dst = Timezone::dst(); bool isDst = Timezone::isDst(Timestamp()); int tzd = Timezone::tzd(); std::string name = Timezone::name(); std::string stdName = Timezone::standardName(); std::string dstName = Timezone::dstName(); return 0; }
#include "Poco/Timestamp.h" #include "Poco/Timespan.h" #include "Poco/DateTimeFormatter.h" #include "Poco/DateTimeFormat.h" using Poco::DateTimeFormatter; using Poco::DateTimeFormat; int main(int argc, char** argv) { Poco::DateTime dt(2006, 10, 22, 15, 22, 34); std::string s(DateTimeFormatter::format(dt, "%e %b %Y %H:%M")); // "22 Oct 2006 15:22" Poco::Timestamp now; s = DateTimeFormatter::format(now, DateTimeFormat::SORTABLE_FORMAT); // "2006-10-30 09:27:44" Poco::Timespan span(5, 11, 33, 0, 0); s = DateTimeFormatter::format(span, "%d days, %H hours, %M minutes"); // "5 days, 11 hours, 33 minutes" return 0; }
#include "Poco/DateTimeParser.h" #include "Poco/DateTime.h" #include "Poco/DateTimeFormat.h" #include "Poco/LocalDateTime.h" #include "Poco/Timestamp.h" using Poco::DateTimeParser; using Poco::DateTimeFormat; using Poco::DateTime; int main(int argc, char** argv) { std::string s("Sat, 1 Jan 2005 12:00:00 GMT"); int tzd; DateTime dt; DateTimeParser::parse(DateTimeFormat::RFC1123_FORMAT, s, dt, tzd); Poco::Timestamp ts = dt.timestamp(); Poco::LocalDateTime ldt(tzd, dt); bool ok = DateTimeParser::tryParse("2006-10-22", dt, tzd); ok = DateTimeParser::tryParse("%e.%n.%Y", "22.10.2006", dt, tzd); return 0; }
class Foundation_API Stopwatch /// A simple facility to measure time intervals /// with microsecond resolution. /// /// Note that Stopwatch is based on the Timestamp /// class. Therefore, if during a Stopwatch run, /// the system time is changed, the measured time /// will not be correct. { public: Stopwatch(); ~Stopwatch(); void start(); /// Starts (or restarts) the stopwatch. void stop(); /// Stops or pauses the stopwatch. void reset(); /// Resets the stopwatch. void restart(); /// Resets and starts the stopwatch. Timestamp::TimeDiff elapsed() const; /// Returns the elapsed time in microseconds /// since the stopwatch started. int elapsedSeconds() const; /// Returns the number of seconds elapsed /// since the stopwatch started. static Timestamp::TimeVal resolution(); /// Returns the resolution of the stopwatch. private: Stopwatch(const Stopwatch&); Stopwatch& operator = (const Stopwatch&); Timestamp _start; Timestamp::TimeDiff _elapsed; bool _running; };