blob: c7424ae931efe1b50dc0acd22bf21b9970956a6f [file] [log] [blame]
/*
* Copyright (C) 2021 Sony Interactive Entertainment Inc.
* Copyright (C) 2021 Apple Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "IntlObject.h"
#include "TemporalObject.h"
namespace JSC {
namespace ISO8601 {
class Duration {
WTF_MAKE_FAST_ALLOCATED(Duration);
public:
using const_iterator = std::array<double, numberOfTemporalUnits>::const_iterator;
Duration() = default;
Duration(double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds)
: m_data {
years,
months,
weeks,
days,
hours,
minutes,
seconds,
milliseconds,
microseconds,
nanoseconds,
}
{ }
#define JSC_DEFINE_ISO8601_DURATION_FIELD(name, capitalizedName) \
double name##s() const { return m_data[static_cast<uint8_t>(TemporalUnit::capitalizedName)]; } \
void set##capitalizedName##s(double value) { m_data[static_cast<uint8_t>(TemporalUnit::capitalizedName)] = value; }
JSC_TEMPORAL_UNITS(JSC_DEFINE_ISO8601_DURATION_FIELD);
#undef JSC_DEFINE_ISO8601_DURATION_FIELD
double& operator[](size_t i) { return m_data[i]; }
const double& operator[](size_t i) const { return m_data[i]; }
double& operator[](TemporalUnit u) { return m_data[static_cast<uint8_t>(u)]; }
const double& operator[](TemporalUnit u) const { return m_data[static_cast<uint8_t>(u)]; }
const_iterator begin() const { return m_data.begin(); }
const_iterator end() const { return m_data.end(); }
void clear() { m_data.fill(0); }
Duration operator-() const
{
Duration result(*this);
for (auto& value : result.m_data)
value = -value;
return result;
}
private:
std::array<double, numberOfTemporalUnits> m_data { };
};
class PlainTime {
WTF_MAKE_FAST_ALLOCATED(PlainTime);
public:
constexpr PlainTime()
: m_millisecond(0)
, m_microsecond(0)
, m_nanosecond(0)
{
}
constexpr PlainTime(unsigned hour, unsigned minute, unsigned second, unsigned millisecond, unsigned microsecond, unsigned nanosecond)
: m_hour(hour)
, m_minute(minute)
, m_second(second)
, m_millisecond(millisecond)
, m_microsecond(microsecond)
, m_nanosecond(nanosecond)
{ }
#define JSC_DEFINE_ISO8601_PLAIN_TIME_FIELD(name, capitalizedName) \
unsigned name() const { return m_##name; }
JSC_TEMPORAL_PLAIN_TIME_UNITS(JSC_DEFINE_ISO8601_PLAIN_TIME_FIELD);
#undef JSC_DEFINE_ISO8601_DURATION_FIELD
friend bool operator==(PlainTime lhs, PlainTime rhs)
{
return lhs.hour() == rhs.hour()
&& lhs.minute() == rhs.minute()
&& lhs.second() == rhs.second()
&& lhs.millisecond() == rhs.millisecond()
&& lhs.microsecond() == rhs.microsecond()
&& lhs.nanosecond() == rhs.nanosecond();
}
private:
uint8_t m_hour { 0 };
uint8_t m_minute { 0 };
uint8_t m_second { 0 };
uint32_t m_millisecond : 10;
uint32_t m_microsecond : 10;
uint32_t m_nanosecond : 10;
};
static_assert(sizeof(PlainTime) <= sizeof(uint64_t));
// Note that PlainDate does not include week unit.
// year can be negative. And month and day starts with 1.
class PlainDate {
WTF_MAKE_FAST_ALLOCATED(PlainDate);
public:
constexpr PlainDate() = default;
constexpr PlainDate(int32_t year, unsigned month, unsigned day)
: m_year(year)
, m_month(month)
, m_day(day)
{
}
int32_t year() const { return m_year; }
uint8_t month() const { return m_month; }
uint8_t day() const { return m_day; }
private:
int32_t m_year { 0 };
uint8_t m_month { 1 };
uint8_t m_day { 1 };
};
using TimeZone = std::variant<TimeZoneID, int64_t>;
// https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaltimezonestring
// Record { [[Z]], [[OffsetString]], [[Name]] }
struct TimeZoneRecord {
bool m_z { false };
std::optional<int64_t> m_offset;
std::variant<Vector<LChar>, int64_t> m_nameOrOffset;
};
// https://tc39.es/proposal-temporal/#sup-isvalidtimezonename
std::optional<TimeZoneID> parseTimeZoneName(StringView);
std::optional<Duration> parseDuration(StringView);
std::optional<int64_t> parseTimeZoneNumericUTCOffset(StringView);
enum class ValidateTimeZoneID { Yes, No };
std::optional<std::tuple<PlainTime, std::optional<TimeZoneRecord>>> parseTime(StringView);
std::optional<std::tuple<PlainDate, std::optional<PlainTime>, std::optional<TimeZoneRecord>>> parseDateTime(StringView);
String formatTimeZoneOffsetString(int64_t);
String temporalTimeToString(PlainTime, std::tuple<Precision, unsigned> precision);
bool isValidDuration(const Duration&);
} // namespace ISO8601
} // namespace JSC