LibWeb: Restore flags to prevent formatting timestamps as local time

The flag to stringify these timestamps as UTC was errantly dropped in
6fb2be96bf. This was causing test-web to
fail in time zones other than GMT+0.
This commit is contained in:
Timothy Flynn 2025-06-25 16:32:24 -04:00 committed by Jelle Raaijmakers
commit 3171d57639
Notes: github-actions[bot] 2025-06-25 21:42:10 +00:00
7 changed files with 63 additions and 18 deletions

View file

@ -2326,7 +2326,7 @@ static String convert_number_to_date_string(double input)
// date string that represents the date that, in UTC, is current input milliseconds after midnight UTC // date string that represents the date that, in UTC, is current input milliseconds after midnight UTC
// on the morning of 1970-01-01 (the time represented by the value "1970-01-01T00:00:00.0Z"). // on the morning of 1970-01-01 (the time represented by the value "1970-01-01T00:00:00.0Z").
auto date = AK::UnixDateTime::from_seconds_since_epoch(input / 1000.); auto date = AK::UnixDateTime::from_seconds_since_epoch(input / 1000.);
return MUST(date.to_string("%Y-%m-%d"sv)); return MUST(date.to_string("%Y-%m-%d"sv, AK::UnixDateTime::LocalTime::No));
} }
// https://html.spec.whatwg.org/multipage/input.html#time-state-(type=time):concept-input-value-number-string // https://html.spec.whatwg.org/multipage/input.html#time-state-(type=time):concept-input-value-number-string

View file

@ -4,7 +4,9 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibJS/Runtime/Date.h>
#include <LibJS/Runtime/VM.h> #include <LibJS/Runtime/VM.h>
#include <LibUnicode/TimeZone.h>
#include <LibWeb/Bindings/InternalsPrototype.h> #include <LibWeb/Bindings/InternalsPrototype.h>
#include <LibWeb/Bindings/Intrinsics.h> #include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/DOM/Document.h> #include <LibWeb/DOM/Document.h>
@ -53,6 +55,17 @@ void Internals::gc()
vm().heap().collect_garbage(); vm().heap().collect_garbage();
} }
WebIDL::ExceptionOr<String> Internals::set_time_zone(StringView time_zone)
{
auto current_time_zone = Unicode::current_time_zone();
if (auto result = Unicode::set_current_time_zone(time_zone); result.is_error())
return vm().throw_completion<JS::InternalError>(MUST(String::formatted("Could not set time zone: {}", result.error())));
JS::clear_system_time_zone_cache();
return current_time_zone;
}
JS::Object* Internals::hit_test(double x, double y) JS::Object* Internals::hit_test(double x, double y)
{ {
auto& active_document = window().associated_document(); auto& active_document = window().associated_document();

View file

@ -23,6 +23,8 @@ public:
void signal_test_is_done(String const& text); void signal_test_is_done(String const& text);
void set_test_timeout(double milliseconds); void set_test_timeout(double milliseconds);
WebIDL::ExceptionOr<String> set_time_zone(StringView time_zone);
void gc(); void gc();
JS::Object* hit_test(double x, double y); JS::Object* hit_test(double x, double y);

View file

@ -8,6 +8,8 @@ interface Internals {
undefined signalTestIsDone(DOMString text); undefined signalTestIsDone(DOMString text);
undefined setTestTimeout(double milliseconds); undefined setTestTimeout(double milliseconds);
DOMString setTimeZone(DOMString timeZone);
undefined gc(); undefined gc();
object hitTest(double x, double y); object hitTest(double x, double y);

View file

@ -146,7 +146,7 @@ static HTTP::HeaderMap response_headers_for_file(StringView path, Optional<time_
if (modified_time.has_value()) { if (modified_time.has_value()) {
auto const datetime = AK::UnixDateTime::from_seconds_since_epoch(modified_time.value()); auto const datetime = AK::UnixDateTime::from_seconds_since_epoch(modified_time.value());
response_headers.set("Last-Modified"sv, datetime.to_byte_string("%a, %d %b %Y %H:%M:%S GMT"sv)); response_headers.set("Last-Modified"sv, datetime.to_byte_string("%a, %d %b %Y %H:%M:%S GMT"sv, AK::UnixDateTime::LocalTime::No));
} }
return response_headers; return response_headers;

View file

@ -4,11 +4,13 @@
4. "1970-01-01T19:46:19.000Z" 4. "1970-01-01T19:46:19.000Z"
5. null 5. null
6. "1970-01-01" 6. "1970-01-01"
7. "2023-12-11" 7. "1970-01-01"
8. Exception: TypeError 8. "2023-12-11"
9. "" 9. "2023-12-11"
10. "18:47:37" 10. Exception: TypeError
11. "18:47:37.100" 11. ""
12. "18:47:37.864" 12. "18:47:37"
13. Exception: TypeError 13. "18:47:37.100"
14. "" 14. "18:47:37.864"
15. Exception: TypeError
16. ""

View file

@ -60,7 +60,20 @@
return input.value; return input.value;
}); });
// 7. Input date set value as date // 7. Input date set value as date (non-UTC time zone)
testPart(() => {
const originalTimeZone = internals.setTimeZone('America/New_York');
const input = document.createElement('input');
input.type = 'date';
input.valueAsDate = new Date(0);
const result = input.value;
internals.setTimeZone(originalTimeZone);
return result;
});
// 8. Input date set value as date
testPart(() => { testPart(() => {
const input = document.createElement('input'); const input = document.createElement('input');
input.type = 'date'; input.type = 'date';
@ -68,7 +81,20 @@
return input.value; return input.value;
}); });
// 8. Input date invalid set value as date // 9. Input date set value as date (non-UTC time zone)
testPart(() => {
const originalTimeZone = internals.setTimeZone('Europe/Paris');
const input = document.createElement('input');
input.type = "date";
input.valueAsDate = new Date(1702320457860);
const result = input.value;
internals.setTimeZone(originalTimeZone);
return result;
});
// 10. Input date invalid set value as date
testPart(() => { testPart(() => {
const input = document.createElement('input'); const input = document.createElement('input');
input.type = 'date'; input.type = 'date';
@ -76,7 +102,7 @@
return input.value; return input.value;
}); });
// 9. Input date null set value as date // 11. Input date null set value as date
testPart(() => { testPart(() => {
const input = document.createElement('input'); const input = document.createElement('input');
input.type = 'date'; input.type = 'date';
@ -84,7 +110,7 @@
return input.value; return input.value;
}); });
// 10. Input time set value as date // 12. Input time set value as date
testPart(() => { testPart(() => {
const input = document.createElement('input'); const input = document.createElement('input');
input.type = 'time'; input.type = 'time';
@ -92,7 +118,7 @@
return input.value; return input.value;
}); });
// 11. Input time set value as date // 13. Input time set value as date
testPart(() => { testPart(() => {
const input = document.createElement('input'); const input = document.createElement('input');
input.type = 'time'; input.type = 'time';
@ -100,7 +126,7 @@
return input.value; return input.value;
}); });
// 12. Input time set value as date // 14. Input time set value as date
testPart(() => { testPart(() => {
const input = document.createElement('input'); const input = document.createElement('input');
input.type = 'time'; input.type = 'time';
@ -108,7 +134,7 @@
return input.value; return input.value;
}); });
// 13. Input time invalid set value as date // 15. Input time invalid set value as date
testPart(() => { testPart(() => {
const input = document.createElement('input'); const input = document.createElement('input');
input.type = 'time'; input.type = 'time';
@ -116,7 +142,7 @@
return input.value; return input.value;
}); });
// 14. Input time null set value as date // 16. Input time null set value as date
testPart(() => { testPart(() => {
const input = document.createElement('input'); const input = document.createElement('input');
input.type = 'time'; input.type = 'time';