17 #include <daw/daw_arith_traits.h>
18 #include <daw/daw_attributes.h>
19 #include <daw/daw_cpp_feature_check.h>
20 #include <daw/daw_cxmath.h>
21 #include <daw/daw_string_view.h>
22 #include <daw/daw_traits.h>
23 #include <daw/daw_uint_buffer.h>
31 namespace parse_utils {
32 template<
typename Result, std::
size_t count>
35 UInt64 result = UInt64( );
36 for( std::size_t n = 0; n < count; ++n ) {
38 to_uint64( json_details::parse_digit( digit_str[n] ) );
45 return static_cast<Result
>( result );
48 template<
typename Result>
51 UInt64 result = UInt64( );
52 unsigned dig = json_details::parse_digit( *digit_str );
57 dig = json_details::parse_digit( *digit_str );
59 return static_cast<Result
>( result );
63 return json_details::parse_digit( c ) < 10U;
68 namespace datetime_details {
70 template<
typename Result,
string_view_bounds_type Bounds>
72 parse_number( daw::basic_string_view<char, Bounds> sv ) {
73 static_assert( daw::numeric_limits<Result>::digits10 >= 4 );
77 if( sv.front( ) ==
'-' ) {
78 if constexpr( daw::is_signed_v<Result> ) {
82 }
else if( sv.front( ) ==
'+' ) {
85 while( not sv.empty( ) ) {
86 auto const dig = json_details::parse_digit( sv.pop_front( ) );
89 result +=
static_cast<Result
>( dig );
96 template<
typename TP = std::chrono::time_point<std::chrono::system_clock,
97 std::chrono::milliseconds>>
99 std::uint32_t dy, std::uint32_t hr,
100 std::uint32_t mn, std::uint32_t se,
102 using Clock =
typename TP::clock;
103 using Duration =
typename TP::duration;
104 constexpr
auto calc =
105 []( std::int32_t y, std::uint32_t m, std::uint32_t d, std::uint32_t h,
106 std::uint32_t min, std::uint32_t s,
108 y -=
static_cast<std::int32_t
>( m ) <= 2;
109 std::int32_t
const era = ( y >= 0 ? y : y - 399 ) / 400;
110 auto const yoe =
static_cast<std::uint32_t
>(
111 static_cast<std::int32_t
>( y ) - era * 400 );
112 auto const doy =
static_cast<std::uint32_t
>(
113 ( 153 * (
static_cast<std::int32_t
>( m ) +
114 (
static_cast<std::int32_t
>( m ) > 2 ? -3 : 9 ) ) +
117 static_cast<std::int32_t
>( d ) - 1 );
118 std::uint32_t
const doe =
119 yoe * 365 + yoe / 4 - yoe / 100 + doy;
120 auto const days_since_epoch =
121 static_cast<int64_t
>( era ) * 146097LL +
122 static_cast<std::int64_t
>( doe ) - 719468LL;
124 using Days = std::chrono::duration<std::int32_t, std::ratio<86400>>;
126 std::chrono::floor<Duration>( std::chrono::nanoseconds( nano ) );
127 return std::chrono::time_point<std::chrono::system_clock,
129 ( Days( days_since_epoch ) + std::chrono::hours( h ) +
130 std::chrono::minutes( min ) +
131 std::chrono::seconds(
static_cast<std::uint32_t
>( s ) ) +
139 auto result = calc( yr, mo, dy, hr, mn, se, ns );
141 if constexpr( std::is_same_v<Clock, std::chrono::system_clock> ) {
144 #if defined( __cpp_lib_chrono ) and __cpp_lib_chrono >= 201907
146 auto const match_duration =
147 std::chrono::time_point_cast<Duration>( result );
148 auto const match_clock =
149 std::chrono::clock_cast<Clock>( match_duration );
155 auto const system_epoch = std::chrono::floor<std::chrono::hours>(
156 std::chrono::system_clock::now( ).time_since_epoch( ) +
157 std::chrono::minutes( 30 ) );
158 auto const clock_epoch = std::chrono::floor<std::chrono::hours>(
159 Clock::now( ).time_since_epoch( ) + std::chrono::minutes( 30 ) );
161 constexpr
auto offset =
162 std::chrono::duration_cast<std::chrono::milliseconds>(
163 clock_epoch - system_epoch );
164 return std::chrono::duration_cast<Duration>( result + offset );
175 template<
string_view_bounds_type Bounds>
177 daw::basic_string_view<char, Bounds> timestamp_str ) {
179 result.day = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
180 std::data( timestamp_str.pop_back( 2U ) ) );
182 ErrorReason::InvalidTimestamp );
184 timestamp_str.remove_suffix( );
186 result.month = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
187 std::data( timestamp_str.pop_back( 2U ) ) );
189 ErrorReason::InvalidTimestamp );
191 timestamp_str.remove_suffix( );
194 datetime_details::parse_number<std::int_least32_t>( timestamp_str );
205 template<
string_view_bounds_type Bounds>
207 daw::basic_string_view<char, Bounds> timestamp_str ) {
209 result.hour = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
210 std::data( timestamp_str.pop_front( 2 ) ) );
212 ErrorReason::InvalidTimestamp );
214 timestamp_str.remove_prefix( );
216 result.minute = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
217 std::data( timestamp_str.pop_front( 2 ) ) );
219 ErrorReason::InvalidTimestamp );
220 if( timestamp_str.empty( ) ) {
224 timestamp_str.remove_prefix( );
226 result.second = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
227 std::data( timestamp_str.pop_front( 2 ) ) );
229 ErrorReason::InvalidTimestamp );
230 if( timestamp_str.empty( ) ) {
234 timestamp_str.remove_prefix( );
236 auto const nanosecond_str = timestamp_str.substr(
237 0, std::min( timestamp_str.size( ), std::size_t{ 9 } ) );
239 datetime_details::parse_number<std::uint64_t>( nanosecond_str );
240 result.nanosecond *= daw::cxmath::pow10( 9 - timestamp_str.size( ) );
244 template<
typename TP,
string_view_bounds_type Bounds>
247 constexpr daw::string_view t_str =
"T";
248 auto const date_str = ts.pop_front_until( t_str );
251 ErrorReason::InvalidTimestamp );
263 if( not( ts.empty( ) or ts.front( ) ==
'Z' ) ) {
265 ErrorReason::InvalidTimestamp );
269 switch( ts.front( ) ) {
279 auto hr_offset = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
282 daw::json::ErrorReason::InvalidTimestamp );
283 if( ts.front( ) ==
':' ) {
286 auto mn_offset = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
289 daw::json::ErrorReason::InvalidTimestamp );
293 hms.
hour -= hr_offset;
297 hms.
hour += hr_offset;
315 template<
typename Clock,
typename Duration>
317 std::chrono::time_point<Clock, Duration>
const &tp ) {
318 auto dur_from_epoch = tp.time_since_epoch( );
320 std::chrono::duration<std::int_least32_t, std::ratio<86400>>;
321 auto const days_since_epoch =
322 std::chrono::duration_cast<Days>( dur_from_epoch );
323 std::int_least32_t z = days_since_epoch.count( );
325 std::int_least32_t
const era = ( z >= 0 ? z : z - 146096 ) / 146097;
327 static_cast<std::uint_least32_t
>( z - era * 146097 );
328 std::uint_least32_t
const yoe =
329 ( doe - doe / 1460 + doe / 36524 - doe / 146096 ) / 365;
330 std::int_least32_t
const y =
331 static_cast<std::int_least32_t
>( yoe ) + era * 400;
332 std::uint_least32_t
const doy =
333 doe - ( 365 * yoe + yoe / 4 - yoe / 100 );
334 std::uint_least32_t
const mp = ( 5 * doy + 2 ) / 153;
335 std::uint_least32_t
const d = doy - ( 153 * mp + 2 ) / 5 + 1;
336 auto const m =
static_cast<std::uint_least32_t
>(
337 static_cast<std::int_least32_t
>( mp ) +
338 (
static_cast<std::int_least32_t
>( mp ) < 10 ? 3 : -9 ) );
340 dur_from_epoch -= days_since_epoch;
342 std::chrono::duration_cast<std::chrono::hours>( dur_from_epoch );
343 dur_from_epoch -= hrs;
345 std::chrono::duration_cast<std::chrono::minutes>( dur_from_epoch );
346 dur_from_epoch -= min;
348 std::chrono::duration_cast<std::chrono::seconds>( dur_from_epoch );
349 dur_from_epoch -= sec;
350 auto const dur = std::chrono::duration_cast<std::chrono::nanoseconds>(
352 return ymdhms{ y + ( m <= 2 ),
355 static_cast<std::uint_least32_t
>( hrs.count( ) ),
356 static_cast<std::uint_least32_t
>( min.count( ) ),
357 static_cast<std::uint_least32_t
>( sec.count( ) ),
358 static_cast<std::uint64_t
>( dur.count( ) ) };
395 template<
typename Duration>
397 std::chrono::time_point<std::chrono::system_clock, Duration> tp ) {
398 using days = std::chrono::duration<long, std::ratio<86400>>;
400 std::chrono::duration_cast<days>( tp.time_since_epoch( ) ).count( );
401 auto const dow = z >= -4L ? ( z + 4L ) % 7L : ( z + 5L ) % 7L + 6L;
423 namespace datetime_details {
424 constexpr std::uint_least32_t month2num( std::string_view ts ) {
426 ErrorReason::InvalidTimestamp );
427 auto const b0 =
static_cast<std::uint_least32_t
>(
428 static_cast<unsigned char>( ts[0] ) );
429 auto const b1 =
static_cast<std::uint_least32_t
>(
430 static_cast<unsigned char>( ts[1] ) );
431 auto const b2 =
static_cast<std::uint_least32_t
>(
432 static_cast<unsigned char>( ts[2] ) );
433 return ( b0 << 16U ) | ( b1 << 8U ) | b2;
439 switch( datetime_details::month2num( ts ) ) {
440 case datetime_details::month2num(
"Jan" ):
442 case datetime_details::month2num(
"Feb" ):
444 case datetime_details::month2num(
"Mar" ):
446 case datetime_details::month2num(
"Apr" ):
448 case datetime_details::month2num(
"May" ):
450 case datetime_details::month2num(
"Jun" ):
452 case datetime_details::month2num(
"Jul" ):
454 case datetime_details::month2num(
"Aug" ):
456 case datetime_details::month2num(
"Sep" ):
458 case datetime_details::month2num(
"Oct" ):
460 case datetime_details::month2num(
"Nov" ):
462 case datetime_details::month2num(
"Dec" ):
#define daw_json_ensure(Bool,...)
Ensure that Bool is true. If false pass rest of args to daw_json_error.
#define DAW_JSON_CPP23_STATIC_CALL_OP
This is in addition to the parse policy. Always do a full name match instead of sometimes relying on ...
DAW_ATTRIB_NOINLINE void daw_json_error(ErrorReason reason)
constexpr std::string_view month_short_name(unsigned m)
constexpr TP parse_iso8601_timestamp(daw::basic_string_view< char, Bounds > ts)
constexpr std::string_view short_day_of_week(std::chrono::time_point< std::chrono::system_clock, Duration > tp)
constexpr TP civil_to_time_point(std::int32_t yr, std::uint32_t mo, std::uint32_t dy, std::uint32_t hr, std::uint32_t mn, std::uint32_t se, std::uint64_t ns)
constexpr time_parts parse_iso_8601_time(daw::basic_string_view< char, Bounds > timestamp_str)
constexpr date_parts parse_iso_8601_date(daw::basic_string_view< char, Bounds > timestamp_str)
constexpr unsigned parse_short_month(std::string_view ts)
constexpr ymdhms time_point_to_civil(std::chrono::time_point< Clock, Duration > const &tp)
constexpr bool is_number(char c)
constexpr Result parse_unsigned2(char const *digit_str)
constexpr Result parse_unsigned(char const *digit_str)
Customization point traits.
std::uint_least32_t second
std::uint_least32_t minute
std::uint_least32_t month
std::uint_least32_t second
std::uint_least32_t minute
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.