srawlins / timezone

Time zone database and time zone aware DateTime object for Dart.
BSD 2-Clause "Simplified" License
102 stars 53 forks source link

parse() and from() ignore location param #127

Open mudar opened 2 years ago

mudar commented 2 years ago

Hi @srawlins,

Thanks for the great work you've done on this library :)

I'm facing an issue when parsing a date that comes from a timezone different from the server's.

When using TZDateTime.parse() or TZDateTime.from() the parsing seems to be done using the machine's location, then converting the result to the param location. Calling tz.setLocalLocation(location2) does not change the result.

I've attached 3 tests, hoping it's less confusing than my explanation.

Example:

void _test_timezones_constructor() async {
  await tz.initializeTimeZone();
  final montreal = tz.getLocation('America/Montreal');
  final losAngeles = tz.getLocation('America/Los_Angeles');

  final tzMontreal = tz.TZDateTime(montreal, 2022, 1, 23, 15);
  final tzLosAngeles = tz.TZDateTime(losAngeles, 2022, 1, 23, 15);

  // this test succeeds :)
  expect(tzMontreal.isAtSameMomentAs(tzLosAngeles), false);
}

void _test_timezones_parser() async {
  await tz.initializeTimeZone();
  final montreal = tz.getLocation('America/Montreal');
  final losAngeles = tz.getLocation('America/Los_Angeles');

  final tzMontreal = tz.TZDateTime.parse(montreal, '2022-01-23 15:00');
  final tzLosAngeles = tz.TZDateTime.parse(losAngeles, '2022-01-23 15:00');

  // this test fails :(
  expect(tzMontreal.isAtSameMomentAs(tzLosAngeles), false);
}

void _test_timezones_set_local_location() async {
  await tz.initializeTimeZone();
  final montreal = tz.getLocation('America/Montreal');
  final losAngeles = tz.getLocation('America/Los_Angeles');
  tz.setLocalLocation(losAngeles);

  final tzMontrealParse = tz.TZDateTime.parse(montreal, '2022-01-23 15:00');
  final tzMontrealConstructor = tz.TZDateTime(montreal, 2022, 1, 23, 15);

  final tzLosAngelesParse = tz.TZDateTime.parse(losAngeles, '2022-01-23 15:00');
  final tzLosAngelesConstructor = tz.TZDateTime(losAngeles, 2022, 1, 23, 15);

  // this succeeds :)
  expect(tzMontrealParse.isAtSameMomentAs(tzMontrealConstructor), true);
  // this fails :()
  expect(tzLosAngelesParse.isAtSameMomentAs(tzLosAngelesConstructor), true);
}

My local timezone is Montreal (EST), my formatted string will be EST too. The heroku server running the app will be Central.

asdasdasde commented 2 years ago

This might help, but I'm not sure if it works on all timezones: (btw. this only works if the timezone is not specified in the formattedDate)

TZDateTime _parse(Location location, String formattedDate) {
  final parsed = DateTime.parse(formattedDate);
  return TZDateTime(
    location,
    parsed.year,
    parsed.month,
    parsed.day,
    parsed.hour,
    parsed.minute,
    parsed.second,
    parsed.millisecond,
    parsed.microsecond,
  );
}
NehaKushwah993 commented 1 year ago

Hi @srawlins,

Thanks for the great work you've done on this library :)

I'm facing an issue when parsing a date that comes from a timezone different from the server's.

When using TZDateTime.parse() or TZDateTime.from() the parsing seems to be done using the machine's location, then converting the result to the param location. Calling tz.setLocalLocation(location2) does not change the result.

I've attached 3 tests, hoping it's less confusing than my explanation.

Example:

void _test_timezones_constructor() async {
  await tz.initializeTimeZone();
  final montreal = tz.getLocation('America/Montreal');
  final losAngeles = tz.getLocation('America/Los_Angeles');

  final tzMontreal = tz.TZDateTime(montreal, 2022, 1, 23, 15);
  final tzLosAngeles = tz.TZDateTime(losAngeles, 2022, 1, 23, 15);

  // this test succeeds :)
  expect(tzMontreal.isAtSameMomentAs(tzLosAngeles), false);
}

void _test_timezones_parser() async {
  await tz.initializeTimeZone();
  final montreal = tz.getLocation('America/Montreal');
  final losAngeles = tz.getLocation('America/Los_Angeles');

  final tzMontreal = tz.TZDateTime.parse(montreal, '2022-01-23 15:00');
  final tzLosAngeles = tz.TZDateTime.parse(losAngeles, '2022-01-23 15:00');

  // this test fails :(
  expect(tzMontreal.isAtSameMomentAs(tzLosAngeles), false);
}

void _test_timezones_set_local_location() async {
  await tz.initializeTimeZone();
  final montreal = tz.getLocation('America/Montreal');
  final losAngeles = tz.getLocation('America/Los_Angeles');
  tz.setLocalLocation(losAngeles);

  final tzMontrealParse = tz.TZDateTime.parse(montreal, '2022-01-23 15:00');
  final tzMontrealConstructor = tz.TZDateTime(montreal, 2022, 1, 23, 15);

  final tzLosAngelesParse = tz.TZDateTime.parse(losAngeles, '2022-01-23 15:00');
  final tzLosAngelesConstructor = tz.TZDateTime(losAngeles, 2022, 1, 23, 15);

  // this succeeds :)
  expect(tzMontrealParse.isAtSameMomentAs(tzMontrealConstructor), true);
  // this fails :()
  expect(tzLosAngelesParse.isAtSameMomentAs(tzLosAngelesConstructor), true);
}

My local timezone is Montreal (EST), my formatted string will be EST too. The heroku server running the app will be Central.

Hi, did you find anything?

martin-braun commented 1 year ago

@asdasdasde Thanks man, this works. What a flawed library. It gives no option to parse a date while specifying the incoming timezone, rather than the targeting timezone, but parsing the incoming date with a native DateTime and feeding all values into the constructor of TZDateTime did work.

Well I said "flawed", but I'm still grateful for this lib, let me tell you that.