// Copyright (c) 2010 Martin Knafve / hMailServer.com. // http://www.hmailserver.com #include "stdafx.h" #include "Time.h" #ifdef _DEBUG #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) #define new DEBUG_NEW #endif namespace HM { Time::Time() { } Time::~Time() { } String Time::GetCurrentDateTime() { SYSTEMTIME pTime; GetLocalTime(&pTime); String sValue; sValue.Format(_T("%d-%.02d-%.02d %.02d:%.02d:%.02d"), pTime.wYear, pTime.wMonth, pTime.wDay, pTime.wHour, pTime.wMinute, pTime.wSecond ); return sValue; } String Time::GetCurrentDateTimeWithMilliseconds() { SYSTEMTIME pTime; GetLocalTime(&pTime); String sValue; sValue.Format(_T("%d-%.02d-%.02d %.02d:%.02d:%.02d.%.03d"), pTime.wYear, pTime.wMonth, pTime.wDay, pTime.wHour, pTime.wMinute, pTime.wSecond, pTime.wMilliseconds ); return sValue; } String Time::GetCurrentDate() { SYSTEMTIME pTime; GetLocalTime(&pTime); String sValue; sValue.Format(_T("%d-%.02d-%.02d"), pTime.wYear, pTime.wMonth, pTime.wDay); return sValue; } String Time::GetTimeStampFromDateTime(const DateTime &dt) { if (dt.GetStatus() == DateTime::invalid) return ""; String sValue; sValue.Format(_T("%d-%.02d-%.02d %.02d:%.02d:%.02d"), dt.GetYear(), dt.GetMonth(), dt.GetDay(), dt.GetHour(), dt.GetMinute(), dt.GetSecond() ); return sValue; } bool Time::SeemsToBeValidYear(const String &sInternalDate) { String sYear = sInternalDate.Mid(0,4); long lYear = _ttoi(sYear); return (lYear > 1980); } int Time::GetUTCRelationMinutes() { // GetTimeZoneInformation returns UTC's // relation to us. But we need to produce // our relation to UTC. Therefore the *-1 below. long lMinutes = 0; TIME_ZONE_INFORMATION tzi; switch (GetTimeZoneInformation(&tzi)) { case TIME_ZONE_ID_STANDARD: case TIME_ZONE_ID_UNKNOWN: lMinutes = tzi.Bias + tzi.StandardBias; break; case TIME_ZONE_ID_DAYLIGHT: lMinutes = tzi.Bias + tzi.DaylightBias; } lMinutes *= -1; return lMinutes; } String Time::GetUTCRelation() { long totalMinutes = GetUTCRelationMinutes(); long hours = abs(totalMinutes / 60); long remainingMinutes = abs(totalMinutes % 60); String sRetVal; if (totalMinutes < 0) sRetVal.Format(_T("-%0.2d%0.2d"), hours, remainingMinutes); else sRetVal.Format(_T("+%0.2d%0.2d"), hours, remainingMinutes); return sRetVal; } bool Time::GetTimeAdjustForTimezone(const String &sTimeZone, int &iHours, int &iMinutes) //---------------------------------------------------------------------------() // DESCRIPTION: // Returns the time modification for a timezone. The number of // hours from UTC. // //---------------------------------------------------------------------------() { if (sTimeZone.IsEmpty()) { // No timezone return false; } double dRetVal = 0; wchar_t s = sTimeZone.GetAt(0); if (s == '+' || s == '-' || isdigit(s)) { bool bPositive = true; String sValue; if (s == '+') sValue = sTimeZone.Mid(1); else if (isdigit(s)) sValue = sTimeZone; else if (s == '-') { bPositive = false; sValue = sTimeZone.Mid(1); } if (sValue.GetLength() != 4) return false; iHours = _ttoi(sValue.Mid(0,2)); iMinutes = _ttoi(sValue.Mid(2,2)); if (bPositive) { iHours *= -1; iMinutes *= -1; } } else if (sTimeZone == _T("UT") || sTimeZone == _T("GMT")) iHours = 0; else if (sTimeZone == _T("EST")) iHours = 5; else if (sTimeZone ==_T( "EDT")) iHours = 4; else if (sTimeZone == _T("CST")) iHours = 6; else if (sTimeZone == _T("CDT")) iHours = 5; else if (sTimeZone == _T("MST")) iHours = 7; else if (sTimeZone == _T("MDT")) iHours = 6; else if (sTimeZone == _T("PST")) iHours = 8; else if (sTimeZone == _T("CET")) iHours = -1; else if (sTimeZone == _T("MET")) iHours = -1; else if (sTimeZone == _T("PDT")) iHours = 7; else { return false; } return true; } String Time::GetCurrentMimeDate() { // Returns a Date: header that has the following format: // Tue, 14 Sep 2004 21:53:33 +0200 SYSTEMTIME pTime; GetLocalTime(&pTime); String sMonth = GetMonthShortName(pTime.wMonth); String sUTC = GetUTCRelation(); String sDayOfWeek = GetCurrentDayName(pTime.wDayOfWeek); String sResult; sResult.Format(_T("%s, %d %s %d %.02d:%.02d:%.02d %s"), sDayOfWeek.c_str(), pTime.wDay, sMonth.c_str(), pTime.wYear, pTime.wHour, pTime.wMinute, pTime.wSecond, sUTC.c_str()); return sResult; } String Time::GetIMAPDateFromMimeHeader(const String &sInDate) //---------------------------------------------------------------------------() // DESCRIPTION: // Convert a date from MIME header format to IMAP date. // // IN: Wed, 22 Dec 2004 21:08:21 +0100 // OUT: 22-Dec-2004 // //---------------------------------------------------------------------------() { std::vector vecParts = StringParser::SplitString(sInDate, " "); if (vecParts.size() < 5) return ""; String sDay = vecParts[1]; String sMonth = vecParts[2]; String sYear = vecParts[3]; String sResult; sResult.Format(_T("%s-%s-%s"), sDay.c_str(), sMonth.c_str(), sYear.c_str()); return sResult; } DateTime Time::GetDateFromMimeHeader(const String &sInDate) //---------------------------------------------------------------------------() // DESCRIPTION: // Convert a date from MIME header format to date // // IN: Wed, 22 Dec 2004 21:08:21 +0100 // OUT: DateTime class // //---------------------------------------------------------------------------() { DateTime dtTmp = GetDateTimeFromMimeHeader(sInDate); // Copy the date (not the time) DateTime dt; dt.SetDate(dtTmp.GetYear(), dtTmp.GetMonth(), dtTmp.GetDay()); return dt; } DateTime Time::GetDateTimeFromMimeHeader(const String &sInDate) //---------------------------------------------------------------------------() // DESCRIPTION: // Convert a date from MIME header format to date. This function is very // flexible when it comes to accepting incorrectly formatted dates. For example // it will accept a date even if it's missing timestamp, zone specifier etc. // // IN: Wed, 22 Dec 2004 21:08:21 +0100 // OUT: DateTime class // //---------------------------------------------------------------------------() { // The string may contain double spaces. If so, remove these now. String sDate = sInDate; sDate.Replace(_T(" "), _T(" ")); std::vector vecParts = StringParser::SplitString(sDate, " "); size_t iNumberOfParts = vecParts.size(); DateTime dt; if (iNumberOfParts < 3) { // A date header should contain at least 4 parts return dt; } unsigned int iFieldIdx = 0; String sFirst = vecParts[iFieldIdx]; if (sFirst.GetLength() > 3) { // Day-of-week is included in the header. iFieldIdx++; } String sDay, sMonth, sYear, sTime, sTimeZone; if (iFieldIdx < iNumberOfParts) sDay = vecParts[iFieldIdx++]; if (iFieldIdx < iNumberOfParts) sMonth = vecParts[iFieldIdx++]; if (iFieldIdx < iNumberOfParts) sYear = vecParts[iFieldIdx++]; if (iFieldIdx < iNumberOfParts) sTime = vecParts[iFieldIdx++]; if (iFieldIdx < iNumberOfParts) sTimeZone = vecParts[iFieldIdx++]; // Convert to numerics int iDayIdx = _ttoi(sDay); int iMonthIdx = GetMonthIndex(sMonth); int iYearIdx = _ttoi(sYear); if (iYearIdx >= 50 && iYearIdx <= 99 ) iYearIdx += 1900; else if (iYearIdx >= 0 && iYearIdx <= 49) iYearIdx += 2000; dt.SetDate(iYearIdx, iMonthIdx, iDayIdx); if (sTime.GetLength() < 5) return dt; // Parse out the time components std::vector vecTime = StringParser::SplitString(sTime, ":"); if (vecTime.size() < 3) return dt; String sHour = vecTime[0]; String sMinute = vecTime[1]; String sSecond = vecTime[2]; int iHour = _ttoi(sHour); int iMinute = _ttoi(sMinute); int iSecond = _ttoi(sSecond); dt.SetDateTime(iYearIdx, iMonthIdx, iDayIdx, iHour, iMinute, iSecond); int iHoursDiff = 0; int iMinutesDiff = 0; if (!GetTimeAdjustForTimezone(sTimeZone, iHoursDiff, iMinutesDiff)) return dt; // Append time DateTimeSpan dtSpan; dtSpan.SetDateTimeSpan(0, iHoursDiff, iMinutesDiff, 0); dt = dt + dtSpan; return dt; } DateTime Time::GetDateFromIMAP(const String &sInDate) //---------------------------------------------------------------------------() // DESCRIPTION: // Convert a date from IMAP date format to date // // IN: 22-Dec-2004 // OUT: DateTime class // //---------------------------------------------------------------------------() { std::vector vecParts = StringParser::SplitString(sInDate, "-"); DateTime dt; if (vecParts.size() < 3) return dt; String sDay = vecParts[0]; String sMonth = vecParts[1]; String sYear = vecParts[2]; int iDayIdx = _ttoi(sDay); int iMonthIdx = GetMonthIndex(sMonth); int iYearIdx = _ttoi(sYear); dt.SetDate(iYearIdx, iMonthIdx, iDayIdx); return dt; } DateTime Time::GetDateFromSystemDate(const String &sInDate) //---------------------------------------------------------------------------() // DESCRIPTION: // Convert a date from a hMailServer system date format to date // // IN: 2004-12-01 12:13:25 // OUT: DateTime class // //---------------------------------------------------------------------------() { DateTime dt; String sYear = sInDate.Mid(0,4); String sMonth = sInDate.Mid(5,2); String sDay = sInDate.Mid(8,2); String sHour = sInDate.Mid(11,2); String sMinute = sInDate.Mid(14,2); String sSecond = sInDate.Mid(17,2); int iYear = _ttoi(sYear); int iMonth = _ttoi(sMonth); int iDay = _ttoi(sDay); int iHour = _ttoi(sHour); int iMinute = _ttoi(sMinute); int iSecond = _ttoi(sSecond); dt.SetDateTime(iYear, iMonth, iDay, iHour, iMinute, iSecond); return dt; } bool Time::IsValidSystemDate(const String &dateString) { String sYear = dateString.Mid(0,4); String sMonth = dateString.Mid(5,2); String sDay = dateString.Mid(8,2); DateTime dt; dt.SetDateTime(_ttoi(sYear), _ttoi(sMonth), _ttoi(sDay), 0, 0, 0); if (dt.GetStatus() == dt.valid) return true; else return false; } String Time::GetIMAPInternalDate(const String &sInternalDate) //---------------------------------------------------------------------------() // DESCRIPTION: // Convert a date from internal date format to mime format. // Internal date format: 2004-03-01 12:00:00 // // Mime date format: // // ::=