/*---------------------------------------------------------------------------*/
/* time.h                                                                    */
/* copyright (c) innovaphone 2016                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

#define EPOCH_YEAR		1970
#define MAX_TRANSITS	(2 * (2037 - EPOCH_YEAR + 1))

typedef struct _timezone_info_t {
    struct {
        dword   utc = 0;
        long    off = 0;
    }   transits[MAX_TRANSITS];
    int numTransits = 0;
    long tzStdOff = 0;
    long tzDstOff = 0;
} timezone_info_t;

typedef struct _time_tm_t {
    int tmSec = 0;			/* Seconds.	[0-60] (1 leap second) */
    int tmMin = 0;			/* Minutes.	[0-59] */
    int tmHour = 0;		    /* Hours.	[0-23] */
    int tmMDay = 0;		    /* Day.		[1-31] */
    int tmMon = 0;			/* Month.	[0-11] */
    int tmYear = 0;		    /* Year	- 1900.  */
    int tmWDay = 0;		    /* Day of week.	[0-6] */
    int tmYDay = 0;		    /* Days in year.[0-365]	*/
    int tmIsDst = 0;		/* DST.		[-1/0/1] */
} time_tm_t;

class ITime {
public:
    static bool ParseTimeZoneString(const char * tz, timezone_info_t & tiOut, int * errPos = NULL);

    static long64 TimeStampMilliseconds();
    static long64 TimeStampMilliseconds(timezone_info_t & ti);
    static long64 UTCTimeToLocalTime(long64 timeMsUtc, timezone_info_t & ti);

    static long64 GetMonotonicTime();
    static long64 GetMonotonicUsec();
    static size_t GetTimeStamp(char * buf, unsigned sz);
    static void GetTimeStruct(long64 timeMs, time_tm_t * t);
    static void GetTimeStruct(long64 timeMs, time_tm_t * t, timezone_info_t & ti);

    static long64 TimeStructToMilliseconds(time_tm_t * ts);
    static bool NormalizeTimeStruct(time_tm_t * ts);

    static size_t FormatTimeStampISO(char * buf, unsigned length, long64 timeMs);
    static size_t FormatTimeStampRFC1123(char * buf, unsigned length, long64 timeMs);
    static size_t FormatTimeStamp(char * buf, unsigned length, const char * formatStr, long64 timeMs);
    static size_t FormatTimeStamp(char * buf, unsigned length, const char * formatStr, long64 timeMs, timezone_info_t & ti);

    static long64 RemoveTime(long64 timeStamp) {
        return (timeStamp / 86400000 * 86400000);
    }

    static bool IsLeapYear(int year) {
        return (year % 4) == 0 && (year % 100 != 0 || year % 400 == 0);
    }

    static int GetDaysOfMonth(int month, int forYear) {
        // Make sure that month is not out of range...
        while (month > 11) {
            month -= 12;
            ++forYear;
        }
        int monthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
        return month == 1 && IsLeapYear(forYear) ? 29 : monthDays[month];
    }
};
