2013-05-03 23:39:52 -04:00
|
|
|
#include "global.h"
|
|
|
|
|
#include "DateTime.h"
|
|
|
|
|
#include "RageUtil.h"
|
|
|
|
|
#include "EnumHelper.h"
|
|
|
|
|
#include "LuaManager.h"
|
|
|
|
|
#include "LocalizedString.h"
|
|
|
|
|
|
|
|
|
|
DateTime::DateTime()
|
|
|
|
|
{
|
|
|
|
|
Init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DateTime::Init()
|
|
|
|
|
{
|
|
|
|
|
ZERO( *this );
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-12 11:09:11 -04:00
|
|
|
bool DateTime::operator<(const DateTime& other) const {
|
|
|
|
|
if (tm_year != other.tm_year) return tm_year < other.tm_year;
|
|
|
|
|
if (tm_mon != other.tm_mon) return tm_mon < other.tm_mon;
|
|
|
|
|
if (tm_mday != other.tm_mday) return tm_mday < other.tm_mday;
|
|
|
|
|
if (tm_hour != other.tm_hour) return tm_hour < other.tm_hour;
|
|
|
|
|
if (tm_min != other.tm_min) return tm_min < other.tm_min;
|
|
|
|
|
if (tm_sec != other.tm_sec) return tm_sec < other.tm_sec;
|
2013-05-03 23:39:52 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-12 11:09:11 -04:00
|
|
|
bool DateTime::operator==(const DateTime& other) const {
|
|
|
|
|
if (tm_year != other.tm_year) return false;
|
|
|
|
|
if (tm_mon != other.tm_mon) return false;
|
|
|
|
|
if (tm_mday != other.tm_mday) return false;
|
|
|
|
|
if (tm_hour != other.tm_hour) return false;
|
|
|
|
|
if (tm_min != other.tm_min) return false;
|
|
|
|
|
if (tm_sec != other.tm_sec) return false;
|
2013-05-03 23:39:52 -04:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-12 11:09:11 -04:00
|
|
|
|
|
|
|
|
bool DateTime::operator!=(const DateTime& other) const {
|
|
|
|
|
return !(*this == other);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DateTime::operator>(const DateTime& other) const {
|
|
|
|
|
if (tm_year != other.tm_year) return tm_year > other.tm_year;
|
|
|
|
|
if (tm_mon != other.tm_mon) return tm_mon > other.tm_mon;
|
|
|
|
|
if (tm_mday != other.tm_mday) return tm_mday > other.tm_mday;
|
|
|
|
|
if (tm_hour != other.tm_hour) return tm_hour > other.tm_hour;
|
|
|
|
|
if (tm_min != other.tm_min) return tm_min > other.tm_min;
|
|
|
|
|
if (tm_sec != other.tm_sec) return tm_sec > other.tm_sec;
|
2013-05-03 23:39:52 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-12 11:09:11 -04:00
|
|
|
|
|
|
|
|
bool DateTime::operator<=(const DateTime& other) const {
|
|
|
|
|
return !(*this > other); // Reuse the > operator
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DateTime::operator>=(const DateTime& other) const {
|
|
|
|
|
return !(*this < other); // Reuse the < operator
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-03 23:39:52 -04:00
|
|
|
DateTime DateTime::GetNowDateTime()
|
|
|
|
|
{
|
|
|
|
|
time_t now = time(nullptr);
|
|
|
|
|
tm tNow;
|
|
|
|
|
localtime_r( &now, &tNow );
|
|
|
|
|
DateTime dtNow;
|
|
|
|
|
#define COPY_M( v ) dtNow.v = tNow.v;
|
|
|
|
|
COPY_M( tm_year );
|
|
|
|
|
COPY_M( tm_mon );
|
|
|
|
|
COPY_M( tm_mday );
|
|
|
|
|
COPY_M( tm_hour );
|
|
|
|
|
COPY_M( tm_min );
|
|
|
|
|
COPY_M( tm_sec );
|
|
|
|
|
#undef COPY_M
|
|
|
|
|
return dtNow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DateTime DateTime::GetNowDate()
|
|
|
|
|
{
|
|
|
|
|
DateTime tNow = GetNowDateTime();
|
|
|
|
|
tNow.StripTime();
|
|
|
|
|
return tNow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DateTime::StripTime()
|
|
|
|
|
{
|
|
|
|
|
tm_hour = 0;
|
|
|
|
|
tm_min = 0;
|
|
|
|
|
tm_sec = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Common SQL/XML format: "YYYY-MM-DD HH:MM:SS"
|
|
|
|
|
RString DateTime::GetString() const
|
|
|
|
|
{
|
|
|
|
|
RString s = ssprintf( "%d-%02d-%02d",
|
|
|
|
|
tm_year+1900,
|
|
|
|
|
tm_mon+1,
|
|
|
|
|
tm_mday );
|
|
|
|
|
|
|
|
|
|
if( tm_hour != 0 ||
|
|
|
|
|
tm_min != 0 ||
|
|
|
|
|
tm_sec != 0 )
|
|
|
|
|
{
|
|
|
|
|
s += ssprintf( " %02d:%02d:%02d",
|
|
|
|
|
tm_hour,
|
|
|
|
|
tm_min,
|
|
|
|
|
tm_sec );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DateTime::FromString( const RString sDateTime )
|
|
|
|
|
{
|
|
|
|
|
Init();
|
|
|
|
|
|
|
|
|
|
int ret;
|
|
|
|
|
|
2025-04-26 17:30:36 -07:00
|
|
|
ret = sscanf( sDateTime.c_str(), "%d-%d-%d %d:%d:%d",
|
2013-05-03 23:39:52 -04:00
|
|
|
&tm_year,
|
|
|
|
|
&tm_mon,
|
|
|
|
|
&tm_mday,
|
|
|
|
|
&tm_hour,
|
|
|
|
|
&tm_min,
|
|
|
|
|
&tm_sec );
|
|
|
|
|
if( ret != 6 )
|
|
|
|
|
{
|
2025-04-26 17:30:36 -07:00
|
|
|
ret = sscanf( sDateTime.c_str(), "%d-%d-%d",
|
2013-05-03 23:39:52 -04:00
|
|
|
&tm_year,
|
|
|
|
|
&tm_mon,
|
|
|
|
|
&tm_mday );
|
|
|
|
|
if( ret != 3 )
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tm_year -= 1900;
|
|
|
|
|
tm_mon -= 1;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RString DayInYearToString( int iDayInYear )
|
|
|
|
|
{
|
|
|
|
|
return ssprintf("DayInYear%03d",iDayInYear);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int StringToDayInYear( RString sDayInYear )
|
|
|
|
|
{
|
|
|
|
|
int iDayInYear;
|
2025-04-26 17:30:36 -07:00
|
|
|
if( sscanf( sDayInYear.c_str(), "DayInYear%d", &iDayInYear ) != 1 )
|
2013-05-03 23:39:52 -04:00
|
|
|
return -1;
|
|
|
|
|
return iDayInYear;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const RString LAST_DAYS_NAME[NUM_LAST_DAYS] =
|
|
|
|
|
{
|
|
|
|
|
"Today",
|
|
|
|
|
"Yesterday",
|
|
|
|
|
"Day2Ago",
|
|
|
|
|
"Day3Ago",
|
|
|
|
|
"Day4Ago",
|
|
|
|
|
"Day5Ago",
|
|
|
|
|
"Day6Ago",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RString LastDayToString( int iLastDayIndex )
|
|
|
|
|
{
|
|
|
|
|
return LAST_DAYS_NAME[iLastDayIndex];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *DAY_OF_WEEK_TO_NAME[DAYS_IN_WEEK] =
|
|
|
|
|
{
|
|
|
|
|
"Sunday",
|
|
|
|
|
"Monday",
|
|
|
|
|
"Tuesday",
|
|
|
|
|
"Wednesday",
|
|
|
|
|
"Thursday",
|
|
|
|
|
"Friday",
|
|
|
|
|
"Saturday",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RString DayOfWeekToString( int iDayOfWeekIndex )
|
|
|
|
|
{
|
|
|
|
|
return DAY_OF_WEEK_TO_NAME[iDayOfWeekIndex];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RString HourInDayToString( int iHourInDayIndex )
|
|
|
|
|
{
|
|
|
|
|
return ssprintf("Hour%02d", iHourInDayIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *MonthNames[] =
|
|
|
|
|
{
|
|
|
|
|
"January",
|
|
|
|
|
"February",
|
|
|
|
|
"March",
|
|
|
|
|
"April",
|
|
|
|
|
"May",
|
|
|
|
|
"June",
|
|
|
|
|
"July",
|
|
|
|
|
"August",
|
|
|
|
|
"September",
|
|
|
|
|
"October",
|
|
|
|
|
"November",
|
|
|
|
|
"December",
|
|
|
|
|
};
|
|
|
|
|
XToString( Month );
|
|
|
|
|
XToLocalizedString( Month );
|
|
|
|
|
LuaXType( Month );
|
|
|
|
|
|
|
|
|
|
RString LastWeekToString( int iLastWeekIndex )
|
|
|
|
|
{
|
|
|
|
|
switch( iLastWeekIndex )
|
|
|
|
|
{
|
|
|
|
|
case 0: return "ThisWeek"; break;
|
|
|
|
|
case 1: return "LastWeek"; break;
|
|
|
|
|
default: return ssprintf("Week%02dAgo",iLastWeekIndex); break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RString LastDayToLocalizedString( int iLastDayIndex )
|
|
|
|
|
{
|
|
|
|
|
RString s = LastDayToString( iLastDayIndex );
|
2025-06-22 23:03:14 -07:00
|
|
|
s.Replace( "Day", "" );
|
|
|
|
|
s.Replace( "Ago", " Ago" );
|
2013-05-03 23:39:52 -04:00
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RString LastWeekToLocalizedString( int iLastWeekIndex )
|
|
|
|
|
{
|
|
|
|
|
RString s = LastWeekToString( iLastWeekIndex );
|
2025-06-22 23:03:14 -07:00
|
|
|
s.Replace( "Week", "" );
|
|
|
|
|
s.Replace( "Ago", " Ago" );
|
2013-05-03 23:39:52 -04:00
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RString HourInDayToLocalizedString( int iHourIndex )
|
|
|
|
|
{
|
|
|
|
|
int iBeginHour = iHourIndex;
|
|
|
|
|
iBeginHour--;
|
|
|
|
|
wrap( iBeginHour, 24 );
|
|
|
|
|
iBeginHour++;
|
|
|
|
|
|
|
|
|
|
return ssprintf("%02d:00+", iBeginHour );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tm AddDays( tm start, int iDaysToMove )
|
|
|
|
|
{
|
|
|
|
|
/*
|
2022-05-25 14:37:07 +02:00
|
|
|
* This causes problems on macOS, which doesn't correctly handle range that are below
|
2013-05-03 23:39:52 -04:00
|
|
|
* their normal values (eg. mday = 0). According to the manpage, it should adjust them:
|
|
|
|
|
*
|
|
|
|
|
* "If structure members are outside their legal interval, they will be normalized (so
|
|
|
|
|
* that, e.g., 40 October is changed into 9 November)."
|
|
|
|
|
*
|
|
|
|
|
* Instead, it appears to simply fail.
|
|
|
|
|
*
|
|
|
|
|
* Refs:
|
|
|
|
|
* http://bugs.php.net/bug.php?id=10686
|
|
|
|
|
* http://sourceforge.net/tracker/download.php?group_id=37892&atid=421366&file_id=79179&aid=91133
|
|
|
|
|
*
|
|
|
|
|
* Note "Log starting 2004-03-07 03:50:42"; mday is 7, and PrintCaloriesBurned calls us
|
|
|
|
|
* with iDaysToMove = -7, resulting in an out-of-range value 0. This seems legal, but
|
2022-05-25 14:37:07 +02:00
|
|
|
* macOS chokes on it.
|
2013-05-03 23:39:52 -04:00
|
|
|
*/
|
|
|
|
|
/* start.tm_mday += iDaysToMove;
|
|
|
|
|
time_t seconds = mktime( &start );
|
|
|
|
|
ASSERT( seconds != (time_t)-1 );
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* This handles DST differently: it returns the time that was exactly n*60*60*24 seconds
|
|
|
|
|
* ago, where the above code always returns the same time of day. I prefer the above
|
|
|
|
|
* behavior, but I'm not sure that it mattersmatters. */
|
|
|
|
|
time_t seconds = mktime( &start );
|
|
|
|
|
seconds += iDaysToMove*60*60*24;
|
|
|
|
|
|
|
|
|
|
tm time;
|
|
|
|
|
localtime_r( &seconds, &time );
|
|
|
|
|
return time;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tm GetYesterday( tm start )
|
|
|
|
|
{
|
|
|
|
|
return AddDays( start, -1 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int GetDayOfWeek( tm time )
|
|
|
|
|
{
|
|
|
|
|
int iDayOfWeek = time.tm_wday;
|
|
|
|
|
ASSERT( iDayOfWeek < DAYS_IN_WEEK );
|
|
|
|
|
return iDayOfWeek;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tm GetNextSunday( tm start )
|
|
|
|
|
{
|
|
|
|
|
return AddDays( start, DAYS_IN_WEEK-GetDayOfWeek(start) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tm GetDayInYearAndYear( int iDayInYearIndex, int iYear )
|
|
|
|
|
{
|
|
|
|
|
/* If iDayInYearIndex is 200, set the date to Jan 200th, and let mktime
|
2022-05-25 14:37:07 +02:00
|
|
|
* round it. This shouldn't suffer from the macOS mktime() issue described
|
2013-05-03 23:39:52 -04:00
|
|
|
* above, since we're not giving it negative values. */
|
|
|
|
|
tm when;
|
|
|
|
|
ZERO( when );
|
|
|
|
|
when.tm_mon = 0;
|
|
|
|
|
when.tm_mday = iDayInYearIndex+1;
|
|
|
|
|
when.tm_year = iYear - 1900;
|
|
|
|
|
time_t then = mktime( &when );
|
|
|
|
|
|
|
|
|
|
localtime_r( &then, &when );
|
|
|
|
|
return when;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LuaFunction( MonthToString, MonthToString( Enum::Check<Month>(L, 1) ) );
|
|
|
|
|
LuaFunction( MonthToLocalizedString, MonthToLocalizedString( Enum::Check<Month>(L, 1) ) );
|
|
|
|
|
LuaFunction( MonthOfYear, GetLocalTime().tm_mon );
|
|
|
|
|
LuaFunction( DayOfMonth, GetLocalTime().tm_mday );
|
|
|
|
|
LuaFunction( Hour, GetLocalTime().tm_hour );
|
|
|
|
|
LuaFunction( Minute, GetLocalTime().tm_min );
|
|
|
|
|
LuaFunction( Second, GetLocalTime().tm_sec );
|
|
|
|
|
LuaFunction( Year, GetLocalTime().tm_year+1900 );
|
|
|
|
|
LuaFunction( Weekday, GetLocalTime().tm_wday );
|
|
|
|
|
LuaFunction( DayOfYear, GetLocalTime().tm_yday );
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* (c) 2001-2004 Chris Danford
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the
|
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
* distribute, and/or sell copies of the Software, and to permit persons to
|
|
|
|
|
* whom the Software is furnished to do so, provided that the above
|
|
|
|
|
* copyright notice(s) and this permission notice appear in all copies of
|
|
|
|
|
* the Software and that both the above copyright notice(s) and this
|
|
|
|
|
* permission notice appear in supporting documentation.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
|
|
|
|
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
|
|
|
|
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
|
|
|
|
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
|
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
|
|
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
*/
|