Atlas - SDL_time.c
Home / ext / SDL / src / time Lines: 1 | Size: 7724 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#include "SDL_time_c.h" 24 25/* The following algorithms are based on those of Howard Hinnant and are in the public domain. 26 * 27 * http://howardhinnant.github.io/date_algorithms.html 28 */ 29 30/* Given a calendar date, returns days since Jan 1 1970, and optionally 31 * the day of the week [0-6, 0 is Sunday] and day of the year [0-365]. 32 */ 33Sint64 SDL_CivilToDays(int year, int month, int day, int *day_of_week, int *day_of_year) 34{ 35 year -= month <= 2; 36 const int era = (year >= 0 ? year : year - 399) / 400; 37 const unsigned yoe = (unsigned)(year - era * 400); // [0, 399] 38 const unsigned doy = (153 * (month > 2 ? month - 3 : month + 9) + 2) / 5 + day - 1; // [0, 365] 39 const unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096] 40 const Sint64 z = (Sint64)(era) * 146097 + (Sint64)(doe)-719468; 41 42 if (day_of_week) { 43 *day_of_week = (int)(z >= -4 ? (z + 4) % 7 : (z + 5) % 7 + 6); 44 } 45 if (day_of_year) { 46 // This algorithm considers March 1 to be the first day of the year, so offset by Jan + Feb. 47 if (doy > 305) { 48 // Day 0 is the first day of the year. 49 *day_of_year = doy - 306; 50 } else { 51 const int doy_offset = 59 + (!(year % 4) && ((year % 100) || !(year % 400))); 52 *day_of_year = doy + doy_offset; 53 } 54 } 55 56 return z; 57} 58 59bool SDL_GetDateTimeLocalePreferences(SDL_DateFormat *dateFormat, SDL_TimeFormat *timeFormat) 60{ 61 // Default to ISO 8061 date format, as it is unambiguous, and 24 hour time. 62 if (dateFormat) { 63 *dateFormat = SDL_DATE_FORMAT_YYYYMMDD; 64 } 65 if (timeFormat) { 66 *timeFormat = SDL_TIME_FORMAT_24HR; 67 } 68 69 SDL_GetSystemTimeLocalePreferences(dateFormat, timeFormat); 70 71 return true; 72} 73 74int SDL_GetDaysInMonth(int year, int month) 75{ 76 static const int DAYS_IN_MONTH[] = { 77 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 78 }; 79 80 if (month < 1 || month > 12) { 81 SDL_SetError("Month out of range [1-12], requested: %i", month); 82 return -1; 83 } 84 85 int days = DAYS_IN_MONTH[month - 1]; 86 87 /* A leap year occurs every 4 years... 88 * but not every 100 years... 89 * except for every 400 years. 90 */ 91 if (month == 2 && (!(year % 4) && ((year % 100) || !(year % 400)))) { 92 ++days; 93 } 94 95 return days; 96} 97 98int SDL_GetDayOfYear(int year, int month, int day) 99{ 100 int dayOfYear; 101 102 if (month < 1 || month > 12) { 103 SDL_SetError("Month out of range [1-12], requested: %i", month); 104 return -1; 105 } 106 if (day < 1 || day > SDL_GetDaysInMonth(year, month)) { 107 SDL_SetError("Day out of range [1-%i], requested: %i", SDL_GetDaysInMonth(year, month), month); 108 return -1; 109 } 110 111 SDL_CivilToDays(year, month, day, NULL, &dayOfYear); 112 return dayOfYear; 113} 114 115int SDL_GetDayOfWeek(int year, int month, int day) 116{ 117 int dayOfWeek; 118 119 if (month < 1 || month > 12) { 120 SDL_SetError("Month out of range [1-12], requested: %i", month); 121 return -1; 122 } 123 if (day < 1 || day > SDL_GetDaysInMonth(year, month)) { 124 SDL_SetError("Day out of range [1-%i], requested: %i", SDL_GetDaysInMonth(year, month), month); 125 return -1; 126 } 127 128 SDL_CivilToDays(year, month, day, &dayOfWeek, NULL); 129 return dayOfWeek; 130} 131 132static bool SDL_DateTimeIsValid(const SDL_DateTime *dt) 133{ 134 if (dt->month < 1 || dt->month > 12) { 135 SDL_SetError("Malformed SDL_DateTime: month out of range [1-12], current: %i", dt->month); 136 return false; 137 } 138 139 const int daysInMonth = SDL_GetDaysInMonth(dt->year, dt->month); 140 if (dt->day < 1 || dt->day > daysInMonth) { 141 SDL_SetError("Malformed SDL_DateTime: day of month out of range [1-%i], current: %i", daysInMonth, dt->month); 142 return false; 143 } 144 if (dt->hour < 0 || dt->hour > 23) { 145 SDL_SetError("Malformed SDL_DateTime: hour out of range [0-23], current: %i", dt->hour); 146 return false; 147 } 148 if (dt->minute < 0 || dt->minute > 59) { 149 SDL_SetError("Malformed SDL_DateTime: minute out of range [0-59], current: %i", dt->minute); 150 return false; 151 } 152 if (dt->second < 0 || dt->second > 60) { 153 SDL_SetError("Malformed SDL_DateTime: second out of range [0-60], current: %i", dt->second); 154 return false; // 60 accounts for a possible leap second. 155 } 156 if (dt->nanosecond < 0 || dt->nanosecond >= SDL_NS_PER_SECOND) { 157 SDL_SetError("Malformed SDL_DateTime: nanosecond out of range [0-999999999], current: %i", dt->nanosecond); 158 return false; 159 } 160 161 return true; 162} 163 164bool SDL_DateTimeToTime(const SDL_DateTime *dt, SDL_Time *ticks) 165{ 166 static const Sint64 max_seconds = SDL_NS_TO_SECONDS(SDL_MAX_TIME) - 1; 167 static const Sint64 min_seconds = SDL_NS_TO_SECONDS(SDL_MIN_TIME) + 1; 168 bool result = true; 169 170 CHECK_PARAM(!dt) { 171 return SDL_InvalidParamError("dt"); 172 } 173 CHECK_PARAM(!ticks) { 174 return SDL_InvalidParamError("ticks"); 175 } 176 CHECK_PARAM(!SDL_DateTimeIsValid(dt)) { 177 // The validation function sets the error string. 178 return false; 179 } 180 181 *ticks = SDL_CivilToDays(dt->year, dt->month, dt->day, NULL, NULL) * SDL_SECONDS_PER_DAY; 182 *ticks += (((dt->hour * 60) + dt->minute) * 60) + dt->second - dt->utc_offset; 183 if (*ticks > max_seconds || *ticks < min_seconds) { 184 *ticks = SDL_clamp(*ticks, min_seconds, max_seconds); 185 result = SDL_SetError("Date out of range for SDL_Time representation; SDL_Time value clamped"); 186 } 187 *ticks = SDL_SECONDS_TO_NS(*ticks) + dt->nanosecond; 188 189 return result; 190} 191 192#define DELTA_EPOCH_1601_100NS (11644473600ll * 10000000ll) // [100 ns] (100 ns units between 1601-01-01 and 1970-01-01, 11644473600 seconds) 193 194void SDL_TimeToWindows(SDL_Time ticks, Uint32 *dwLowDateTime, Uint32 *dwHighDateTime) 195{ 196 /* Convert nanoseconds to Win32 ticks. 197 * SDL_Time has a range of roughly 292 years, so even SDL_MIN_TIME can't underflow the Win32 epoch. 198 */ 199 const Uint64 wtime = (Uint64)((ticks / 100) + DELTA_EPOCH_1601_100NS); 200 201 if (dwLowDateTime) { 202 *dwLowDateTime = (Uint32)wtime; 203 } 204 205 if (dwHighDateTime) { 206 *dwHighDateTime = (Uint32)(wtime >> 32); 207 } 208} 209 210SDL_Time SDL_TimeFromWindows(Uint32 dwLowDateTime, Uint32 dwHighDateTime) 211{ 212 static const Uint64 wintime_min = (Uint64)((SDL_MIN_TIME / 100) + DELTA_EPOCH_1601_100NS); 213 static const Uint64 wintime_max = (Uint64)((SDL_MAX_TIME / 100) + DELTA_EPOCH_1601_100NS); 214 215 Uint64 wtime = (((Uint64)dwHighDateTime << 32) | dwLowDateTime); 216 217 // Clamp the windows time range to the SDL_Time min/max 218 wtime = SDL_clamp(wtime, wintime_min, wintime_max); 219 220 return (SDL_Time)(wtime - DELTA_EPOCH_1601_100NS) * 100; 221} 222[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.