1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-20 14:55:08 +00:00
serenity/Userland/Libraries/LibJS/Runtime/Date.h
Timothy Flynn d83ce7dd0b LibJS: Re-implement the Date constructor / prototype for spec compliance
First, this adds a constructor to the Date object to be created from a
plain double. This is a first step to removing Core::DateTime as the
basis for the Date object. A subsequent commit will remove the now-
unused data from the object.

Next, this implements the constructor in accordance to the spec. The
constructor when NewTarget is undefined no longer allocates a Date on
the heap. The other constructor properly uses recently created AOs to
handle time zone and ensure the created [[DateValue]] is valid. Other
methods on the constructor (Date.now) have not been touched yet.

Last, the prototype is reimplemented. Again, we use other AOs to handle
time zones and time clipping. Not all prototypes are fixed; most of them
are, but a few (e.g. Date.prototype.getTimezoneOffset) were not fixed,
but left in a mostly unimplemented state for another commit.

In all of the above, spec comments are added. This is a rather large
change; but it's tough to do any of these parts individually without
breaking everything else.
2022-01-15 20:13:48 +01:00

117 lines
3.8 KiB
C++

/*
* Copyright (c) 2020-2021, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2022, Tim Flynn <trflynn89@pm.me>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Math.h>
#include <LibCore/DateTime.h>
#include <LibJS/Runtime/Object.h>
namespace JS {
class Date final : public Object {
JS_OBJECT(Date, Object);
public:
static constexpr double time_clip = 8.64e15;
static Date* create(GlobalObject&, Core::DateTime, i16 milliseconds, bool is_invalid);
static Date* create(GlobalObject&, double date_value);
static Date* now(GlobalObject&);
Date(Core::DateTime datetime, i16 milliseconds, bool is_invalid, Object& prototype);
Date(double date_value, Object& prototype);
virtual ~Date() override;
double date_value() const { return m_date_value; }
void set_date_value(double value) { m_date_value = value; }
Core::DateTime& datetime() { return m_datetime; }
const Core::DateTime& datetime() const { return m_datetime; }
int date() const { return datetime().day(); }
int day() const { return datetime().weekday(); }
int hours() const { return datetime().hour(); }
i16 milliseconds() const { return m_milliseconds; }
int minutes() const { return datetime().minute(); }
int month() const { return datetime().month() - 1; }
int seconds() const { return datetime().second(); }
double time() const { return datetime().timestamp() * 1000.0 + milliseconds(); }
int year() const { return datetime().year(); }
bool is_invalid() const { return m_is_invalid; }
void set_is_invalid(bool value) { m_is_invalid = value; }
int utc_date() const;
int utc_day() const;
int utc_full_year() const;
int utc_hours() const;
int utc_milliseconds() const { return milliseconds(); }
int utc_minutes() const;
int utc_month() const;
int utc_seconds() const;
void set_milliseconds(i16 milliseconds)
{
m_milliseconds = milliseconds;
}
// FIXME: Support %04Y in Core::DateTime::to_string()
String date_string() const { return String::formatted(m_datetime.to_string("%a %b %d {:04}"), m_datetime.year()); }
// FIXME: Deal with timezones once SerenityOS has a working tzset(3)
String time_string() const { return m_datetime.to_string("%T GMT+0000 (UTC)"); }
String string() const
{
if (is_invalid())
return "Invalid Date";
return String::formatted("{} {}", date_string(), time_string());
}
String gmt_date_string() const;
String iso_date_string() const;
// FIXME: One day, implement real locale support. Until then, everyone gets what the Clock Applet displays.
String locale_date_string() const { return m_datetime.to_string("%Y-%m-%d"); }
String locale_string() const { return m_datetime.to_string(); }
String locale_time_string() const { return m_datetime.to_string("%H:%M:%S"); }
private:
tm to_utc_tm() const;
double m_date_value { 0 }; // [[DateValue]]
Core::DateTime m_datetime;
i16 m_milliseconds;
bool m_is_invalid { false };
};
u16 day_within_year(double);
u8 date_from_time(double);
u16 days_in_year(i32);
double day_from_year(i32);
double time_from_year(i32);
i32 year_from_time(double);
bool in_leap_year(double);
u8 month_from_time(double);
u8 hour_from_time(double);
u8 min_from_time(double);
u8 sec_from_time(double);
u16 ms_from_time(double);
u8 week_day(double);
double local_tza(double time, bool is_utc, Optional<StringView> time_zone_override = {});
double local_time(double time);
double utc_time(double time);
double day(double);
double time_within_day(double);
Value make_time(GlobalObject& global_object, Value hour, Value min, Value sec, Value ms);
Value make_day(GlobalObject& global_object, Value year, Value month, Value date);
Value make_date(Value day, Value time);
Value time_clip(GlobalObject& global_object, Value time);
}