100 std::uint32_t dy, std::uint32_t hr,
101 std::uint32_t mn, std::uint32_t se,
102 std::uint64_t attosecond ) {
103 using Clock =
typename TP::clock;
104 using Duration =
typename TP::duration;
105 DAW_CPP23_STATIC_LOCAL
constexpr auto calc =
113 y -=
static_cast<std::int32_t
>( m ) <= 2;
114 std::int32_t
const era = ( y >= 0 ? y : y - 399 ) / 400;
115 auto const yoe =
static_cast<std::uint32_t
>(
116 static_cast<std::int32_t
>( y ) - era * 400 );
117 auto const doy =
static_cast<std::uint32_t
>(
118 ( 153 * (
static_cast<std::int32_t
>( m ) +
119 (
static_cast<std::int32_t
>( m ) > 2 ? -3 : 9 ) ) +
122 static_cast<std::int32_t
>( d ) - 1 );
123 std::uint32_t
const doe =
124 yoe * 365 + yoe / 4 - yoe / 100 + doy;
125 auto const days_since_epoch =
126 static_cast<int64_t
>( era ) * 146097LL +
127 static_cast<std::int64_t
>( doe ) - 719468LL;
129 auto const dur = std::chrono::floor<Duration>(
130 attoseconds(
static_cast<std::int64_t
>( atto ) ) );
131 auto const whole_seconds =
132 std::chrono::seconds( days_since_epoch * 86400LL +
133 static_cast<std::int64_t
>( h ) * 3600LL +
134 static_cast<std::int64_t
>( min ) * 60LL +
135 static_cast<std::int64_t
>( s ) );
136 return std::chrono::time_point<std::chrono::system_clock,
138 ( std::chrono::duration_cast<Duration>( whole_seconds ) +
146 auto result = calc( yr, mo, dy, hr, mn, se, attosecond );
148 if constexpr( std::is_same_v<Clock, std::chrono::system_clock> ) {
151#if defined( __cpp_lib_chrono ) and __cpp_lib_chrono >= 201907
153 auto const match_duration =
154 std::chrono::time_point_cast<Duration>( result );
155 auto const match_clock =
156 std::chrono::clock_cast<Clock>( match_duration );
162 auto const system_epoch = std::chrono::floor<std::chrono::hours>(
163 std::chrono::system_clock::now( ).time_since_epoch( ) +
164 std::chrono::minutes( 30 ) );
165 auto const clock_epoch = std::chrono::floor<std::chrono::hours>(
166 Clock::now( ).time_since_epoch( ) + std::chrono::minutes( 30 ) );
168 DAW_CPP23_STATIC_LOCAL
constexpr auto offset =
169 std::chrono::duration_cast<std::chrono::milliseconds>(
170 clock_epoch - system_epoch );
171 return std::chrono::duration_cast<Duration>( result + offset );
185 result.
day = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
186 std::data( timestamp_str.pop_back( 2U ) ) );
188 ErrorReason::InvalidTimestamp );
189 if( not parse_utils::is_number( timestamp_str.back( ) ) ) {
190 timestamp_str.remove_suffix( );
192 result.month = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
193 std::data( timestamp_str.pop_back( 2U ) ) );
195 ErrorReason::InvalidTimestamp );
196 if( not parse_utils::is_number( timestamp_str.back( ) ) ) {
197 timestamp_str.remove_suffix( );
200 datetime_details::parse_number<std::int_least32_t>( timestamp_str );
201 auto max_day = std::uint32_t{ 31 };
202 if( result.month == 2 ) {
203 auto const is_leap_year =
204 result.year % 4 == 0 and
205 ( result.year % 100 != 0 or result.year % 400 == 0 );
206 max_day = is_leap_year ? 29U : 28U;
207 }
else if( result.month == 4 or result.month == 6 or
208 result.month == 9 or result.month == 11 ) {
212 ErrorReason::InvalidTimestamp );
226 result.
hour = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
227 std::data( timestamp_str.pop_front( 2 ) ) );
229 if( not parse_utils::is_number( timestamp_str.front( ) ) ) {
230 timestamp_str.remove_prefix( );
232 result.minute = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
233 std::data( timestamp_str.pop_front( 2 ) ) );
235 if( timestamp_str.empty( ) ) {
237 ErrorReason::InvalidTimestamp );
240 if( not parse_utils::is_number( timestamp_str.front( ) ) ) {
241 timestamp_str.remove_prefix( );
243 result.second = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
244 std::data( timestamp_str.pop_front( 2 ) ) );
246 if( timestamp_str.empty( ) ) {
248 ( result.minute == 0 and result.second == 0 ),
249 ErrorReason::InvalidTimestamp );
253 ErrorReason::InvalidTimestamp );
254 timestamp_str.remove_prefix( );
256 ErrorReason::InvalidTimestamp );
257 for(
char const c : timestamp_str ) {
259 ErrorReason::InvalidTimestamp );
261 auto const precision =
262 (std::min)( { timestamp_str.size( ), std::size_t{ 18 } } );
263 auto const attosecond_str = timestamp_str.substr( 0, precision );
265 datetime_details::parse_number<std::uint64_t>( attosecond_str );
266 result.attosecond *= daw::cxmath::pow10( 18 - precision );
269 ( result.minute == 0 and result.second == 0 and
270 result.attosecond == 0 ),
271 ErrorReason::InvalidTimestamp );
277 DAW_CPP23_STATIC_LOCAL
constexpr daw::string_view t_str =
"T";
278 auto const date_str = ts.pop_front_until( t_str );
281 ErrorReason::InvalidTimestamp );
286 auto time_str = ts.pop_front_until(
288 return not( parse_utils::is_number( c ) | ( c ==
':' ) |
295 auto const local_tp = civil_to_time_point<TP>( ymd.
year,
302 if( ts.empty( ) or ts.front( ) ==
'Z' ) {
306 ErrorReason::InvalidTimestamp );
309 switch( ts.front( ) ) {
319 auto hr_offset_str = ts.pop_front( 2 );
320 auto mn_offset_str = daw::string_view{ };
321 if( hr_offset_str.size( ) == 4 ) {
322 mn_offset_str = hr_offset_str.pop_back( 2 );
325 parse_utils::is_number( hr_offset_str[0] ) and
326 parse_utils::is_number( hr_offset_str[1] ),
327 ErrorReason::InvalidTimestamp );
329 auto const hr_offset =
330 parse_utils::parse_unsigned<std::uint_least32_t, 2>(
331 std::data( hr_offset_str ) );
333 if( not ts.empty( ) and ts.front( ) ==
':' ) {
336 if( mn_offset_str.empty( ) ) {
337 mn_offset_str = ts.pop_front( 2 );
340 parse_utils::is_number( mn_offset_str[0] ) and
341 parse_utils::is_number( mn_offset_str[1] ),
342 ErrorReason::InvalidTimestamp );
343 auto const mn_offset =
344 parse_utils::parse_unsigned<std::uint_least32_t, 2>(
345 std::data( mn_offset_str ) );
348 if( hr_offset == 0 and mn_offset == 0 ) {
349 return std::chrono::time_point_cast<typename TP::duration>(
355 auto const offset = std::chrono::seconds{
356 static_cast<std::chrono::seconds::rep
>( hr_offset ) * 3600 +
357 static_cast<std::chrono::seconds::rep
>( mn_offset ) * 60 };
361 return std::chrono::time_point_cast<typename TP::duration>(
363 std::chrono::duration_cast<typename TP::duration>( offset );
366 return std::chrono::time_point_cast<typename TP::duration>( local_tp ) +
367 std::chrono::duration_cast<typename TP::duration>( offset );
382 auto dur_from_epoch = tp.time_since_epoch( );
384 std::chrono::duration<std::int_least32_t, std::ratio<86400>>;
385 auto const whole_seconds =
386 std::chrono::floor<std::chrono::seconds>( dur_from_epoch );
387 auto const days_since_epoch = std::chrono::floor<Days>( whole_seconds );
388 std::int_least32_t z = days_since_epoch.count( );
390 std::int_least32_t
const era = ( z >= 0 ? z : z - 146096 ) / 146097;
392 static_cast<std::uint_least32_t
>( z - era * 146097 );
393 std::uint_least32_t
const yoe =
394 ( doe - doe / 1460 + doe / 36524 - doe / 146096 ) / 365;
395 std::int_least32_t
const y =
396 static_cast<std::int_least32_t
>( yoe ) + era * 400;
397 std::uint_least32_t
const doy =
398 doe - ( 365 * yoe + yoe / 4 - yoe / 100 );
399 std::uint_least32_t
const mp = ( 5 * doy + 2 ) / 153;
400 std::uint_least32_t
const d = doy - ( 153 * mp + 2 ) / 5 + 1;
401 auto const m =
static_cast<std::uint_least32_t
>(
402 static_cast<std::int_least32_t
>( mp ) +
403 (
static_cast<std::int_least32_t
>( mp ) < 10 ? 3 : -9 ) );
407 std::chrono::duration_cast<std::chrono::seconds>( days_since_epoch );
409 std::chrono::duration_cast<std::chrono::hours>( dur_in_day );
412 std::chrono::duration_cast<std::chrono::minutes>( dur_in_day );
415 std::chrono::duration_cast<std::chrono::seconds>( dur_in_day );
416 auto const subseconds =
418 std::chrono::duration_cast<Duration>( whole_seconds );
419 auto const dur = std::chrono::duration_cast<attoseconds>( subseconds );
420 return ymdhms{ y + ( m <= 2 ),
423 static_cast<std::uint_least32_t
>( hrs.count( ) ),
424 static_cast<std::uint_least32_t
>( min.count( ) ),
425 static_cast<std::uint_least32_t
>( sec.count( ) ),
426 static_cast<std::uint64_t
>( dur.count( ) ) };
466 std::chrono::time_point<std::chrono::system_clock, Duration> tp ) {
467 using days = std::chrono::duration<long, std::ratio<86400>>;
469 std::chrono::duration_cast<days>( tp.time_since_epoch( ) ).count( );
470 auto const dow = z >= -4L ? ( z + 4L ) % 7L : ( z + 5L ) % 7L + 6L;
489 ErrorReason::InvalidTimestamp );
509 switch( datetime_details::month2num( ts ) ) {
510 case datetime_details::month2num(
"Jan" ):
512 case datetime_details::month2num(
"Feb" ):
514 case datetime_details::month2num(
"Mar" ):
516 case datetime_details::month2num(
"Apr" ):
518 case datetime_details::month2num(
"May" ):
520 case datetime_details::month2num(
"Jun" ):
522 case datetime_details::month2num(
"Jul" ):
524 case datetime_details::month2num(
"Aug" ):
526 case datetime_details::month2num(
"Sep" ):
528 case datetime_details::month2num(
"Oct" ):
530 case datetime_details::month2num(
"Nov" ):
532 case datetime_details::month2num(
"Dec" ):
537 ErrorReason::InvalidTimestamp );