13 #include <daw/daw_arith_traits.h>
14 #include <daw/daw_string_view.h>
22 template<
typename Result, std::
size_t count>
24 UInt64 result = UInt64( );
25 for( std::size_t n = 0; n < count; ++n ) {
27 result += to_uint64( json_details::parse_digit( digit_str[n] ) );
29 return static_cast<Result
>( result );
32 template<
typename Result>
34 UInt64 result = UInt64( );
35 unsigned dig = json_details::parse_digit( *digit_str );
40 dig = json_details::parse_digit( *digit_str );
42 return static_cast<Result
>( result );
46 return json_details::parse_digit( c ) < 10U;
51 namespace datetime_details {
53 template<
typename Result,
typename Bounds, std::ptrdiff_t Ex>
55 parse_number( daw::basic_string_view<char, Bounds, Ex> sv ) {
56 static_assert( daw::numeric_limits<Result>::digits10 >= 4 );
60 if( sv.front( ) ==
'-' ) {
61 if constexpr( daw::is_signed_v<Result> ) {
65 }
else if( sv.front( ) ==
'+' ) {
68 while( not sv.empty( ) ) {
69 auto const dig = json_details::parse_digit( sv.pop_front( ) );
72 result +=
static_cast<Result
>( dig );
79 template<
typename Clock = std::chrono::system_clock,
80 typename Duration = std::chrono::milliseconds>
81 constexpr std::chrono::time_point<Clock, Duration>
83 std::uint_least32_t dy, std::uint_least32_t hr,
84 std::uint_least32_t mn, std::uint_least32_t se,
85 std::uint_least32_t ms ) {
86 constexpr
auto calc = []( std::int_least32_t y, std::uint_least32_t m,
87 std::uint_least32_t d, std::uint_least32_t h,
88 std::uint_least32_t min, std::uint_least32_t s,
89 std::uint_least32_t mil ) {
90 y -=
static_cast<std::int_least32_t
>( m ) <= 2;
91 std::int_least32_t
const era = ( y >= 0 ? y : y - 399 ) / 400;
92 auto const yoe =
static_cast<std::uint_least32_t
>(
93 static_cast<std::int_least32_t
>( y ) - era * 400 );
94 auto const doy =
static_cast<std::uint_least32_t
>(
95 ( 153 * (
static_cast<std::int_least32_t
>( m ) +
96 (
static_cast<std::int_least32_t
>( m ) > 2 ? -3 : 9 ) ) +
99 static_cast<std::int_least32_t
>( d ) - 1 );
100 std::uint_least32_t
const doe =
101 yoe * 365 + yoe / 4 - yoe / 100 + doy;
102 std::int_least32_t
const days_since_epoch =
103 era * 146097 +
static_cast<std::int_least32_t
>( doe ) - 719468;
105 using Days = std::chrono::duration<std::int_least32_t, std::ratio<86400>>;
106 return std::chrono::time_point<std::chrono::system_clock,
107 std::chrono::milliseconds>{ } +
108 ( Days( days_since_epoch ) + std::chrono::hours( h ) +
109 std::chrono::minutes( min ) +
110 std::chrono::seconds(
static_cast<std::uint_least32_t
>( s ) ) +
111 std::chrono::milliseconds( mil ) );
117 auto result = calc( yr, mo, dy, hr, mn, se, ms );
118 #if defined( __cpp_lib_chrono ) and __cpp_lib_chrono >= 201907
120 return std::chrono::duration_cast<Duration>(
121 std::chrono::clock_cast<Clock>( result ) );
123 if constexpr( std::is_same_v<Clock, std::chrono::system_clock> ) {
129 auto const system_epoch = std::chrono::floor<std::chrono::hours>(
130 std::chrono::system_clock::now( ).time_since_epoch( ) +
131 std::chrono::minutes( 30 ) );
132 auto const clock_epoch = std::chrono::floor<std::chrono::hours>(
133 Clock::now( ).time_since_epoch( ) + std::chrono::minutes( 30 ) );
135 constexpr
auto offset =
136 std::chrono::duration_cast<std::chrono::milliseconds>( clock_epoch -
138 return std::chrono::duration_cast<Duration>( result + offset );
149 template<
typename Bounds, std::ptrdiff_t Ex>
151 daw::basic_string_view<char, Bounds, Ex> timestamp_str ) {
153 result.
day = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
154 timestamp_str.pop_back( 2U ).data( ) );
156 timestamp_str.remove_suffix( );
158 result.month = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
159 timestamp_str.pop_back( 2U ).data( ) );
161 timestamp_str.remove_suffix( );
164 datetime_details::parse_number<std::int_least32_t>( timestamp_str );
175 template<
typename Bounds, std::ptrdiff_t Ex>
177 daw::basic_string_view<char, Bounds, Ex> timestamp_str ) {
179 result.
hour = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
180 timestamp_str.pop_front( 2 ).data( ) );
182 timestamp_str.remove_prefix( );
184 result.minute = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
185 timestamp_str.pop_front( 2 ).data( ) );
186 if( timestamp_str.empty( ) ) {
190 timestamp_str.remove_prefix( );
192 result.second = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
193 timestamp_str.pop_front( 2 ).data( ) );
194 if( timestamp_str.empty( ) ) {
198 timestamp_str.remove_prefix( );
200 result.millisecond = datetime_details::parse_number<std::uint_least32_t>(
201 timestamp_str.pop_front( 3 ) );
205 template<
typename Bounds, std::ptrdiff_t Ex>
206 constexpr std::chrono::time_point<std::chrono::system_clock,
207 std::chrono::milliseconds>
209 constexpr daw::string_view t_str =
"T";
210 auto const date_str = ts.pop_front( t_str );
217 auto time_str = ts.pop_front( [](
char c ) {
222 if( not( ts.empty( ) or ts.front( ) ==
'Z' ) ) {
224 ErrorReason::InvalidTimestamp );
226 bool const sign = ts.front( ) ==
'+';
229 parse_utils::parse_unsigned<std::uint_least32_t, 2>( ts.data( ) );
230 if( ts.front( ) ==
':' ) {
234 parse_utils::parse_unsigned<std::uint_least32_t, 2>( ts.data( ) );
238 hms.
hour -= hr_offset;
242 hms.
hour += hr_offset;
259 template<
typename Clock,
typename Duration>
262 auto dur_from_epoch = tp.time_since_epoch( );
263 using Days = std::chrono::duration<std::int_least32_t, std::ratio<86400>>;
264 auto const days_since_epoch =
265 std::chrono::duration_cast<Days>( dur_from_epoch );
266 std::int_least32_t z = days_since_epoch.count( );
268 std::int_least32_t
const era = ( z >= 0 ? z : z - 146096 ) / 146097;
270 static_cast<std::uint_least32_t
>( z - era * 146097 );
271 std::uint_least32_t
const yoe =
272 ( doe - doe / 1460 + doe / 36524 - doe / 146096 ) / 365;
273 std::int_least32_t
const y =
274 static_cast<std::int_least32_t
>( yoe ) + era * 400;
275 std::uint_least32_t
const doy =
276 doe - ( 365 * yoe + yoe / 4 - yoe / 100 );
277 std::uint_least32_t
const mp = ( 5 * doy + 2 ) / 153;
278 std::uint_least32_t
const d = doy - ( 153 * mp + 2 ) / 5 + 1;
279 auto const m =
static_cast<std::uint_least32_t
>(
280 static_cast<std::int_least32_t
>( mp ) +
281 (
static_cast<std::int_least32_t
>( mp ) < 10 ? 3 : -9 ) );
283 dur_from_epoch -= days_since_epoch;
285 std::chrono::duration_cast<std::chrono::hours>( dur_from_epoch );
286 dur_from_epoch -= hrs;
288 std::chrono::duration_cast<std::chrono::minutes>( dur_from_epoch );
289 dur_from_epoch -= min;
291 std::chrono::duration_cast<std::chrono::seconds>( dur_from_epoch );
292 dur_from_epoch -= sec;
294 std::chrono::duration_cast<std::chrono::milliseconds>( dur_from_epoch );
295 return ymdhms{ y + ( m <= 2 ),
298 static_cast<std::uint_least32_t
>( hrs.count( ) ),
299 static_cast<std::uint_least32_t
>( min.count( ) ),
300 static_cast<std::uint_least32_t
>( sec.count( ) ),
301 static_cast<std::uint_least32_t
>( ms.count( ) ) };
337 template<
typename Duration>
339 std::chrono::time_point<std::chrono::system_clock, Duration> tp ) {
340 using days = std::chrono::duration<long, std::ratio<86400>>;
342 std::chrono::duration_cast<days>( tp.time_since_epoch( ) ).count( );
343 auto const dow = z >= -4L ? ( z + 4L ) % 7L : ( z + 5L ) % 7L + 6L;
364 std::chrono::time_point<std::chrono::system_clock,
365 std::chrono::milliseconds>( ) ) ==
368 namespace datetime_details {
369 constexpr std::uint_least32_t month2num( std::string_view ts ) {
372 static_cast<std::uint_least32_t
>(
static_cast<unsigned char>( ts[0] ) );
374 static_cast<std::uint_least32_t
>(
static_cast<unsigned char>( ts[1] ) );
376 static_cast<std::uint_least32_t
>(
static_cast<unsigned char>( ts[2] ) );
377 return ( b0 << 16U ) | ( b1 << 8U ) | b2;
383 switch( datetime_details::month2num( ts ) ) {
384 case datetime_details::month2num(
"Jan" ):
386 case datetime_details::month2num(
"Feb" ):
388 case datetime_details::month2num(
"Mar" ):
390 case datetime_details::month2num(
"Apr" ):
392 case datetime_details::month2num(
"May" ):
394 case datetime_details::month2num(
"Jun" ):
396 case datetime_details::month2num(
"Jul" ):
398 case datetime_details::month2num(
"Aug" ):
400 case datetime_details::month2num(
"Sep" ):
402 case datetime_details::month2num(
"Oct" ):
404 case datetime_details::month2num(
"Nov" ):
406 case datetime_details::month2num(
"Dec" ):