Skip to content

Instantly share code, notes, and snippets.

@alabamenhu
Created October 15, 2022 22:04
Show Gist options
  • Save alabamenhu/fe0ef49bc0d4ec0f0a7ea428c32232a6 to your computer and use it in GitHub Desktop.
Save alabamenhu/fe0ef49bc0d4ec0f0a7ea428c32232a6 to your computer and use it in GitHub Desktop.
Timezone live demo
use v6.d;
unit module Live;
# Determine user's timezone
use User::Timezone:auth<zef:guifa>;
# Find out when shifts happen
use Timezones::ZoneInfo:auth<zef:guifa> :tz-shift, :constants;
# Meta info class
use Timezones::Live::ShiftInfo:auth<zef:guifa>;
my $supplier = Supplier.new;
my $zone = timezone-data user-timezone;
sub timezone-shifts is export { $supplier.Supply };
start loop {
my $time = now.to-posix.head.Int;
my $change-time = next-tz-shift $time, $zone;
my $old-offset = $*TZ;
my $new-offset;
# Zones like Etc/GMT that have one offset year round will return
# max-time. There's no need to keep this loop active.
last if $change-time == max-time;
# Do nothing until the next timezone change (so, realistically, this won't
# be called in most scripts).
await Promise.at(Instant.from-posix: $change-time);
# Get our new offset, set $*TZ to it (so things like DateTime pick up on it)
# and then signal to any subscribed to our suppl
$new-offset = calendar-from-posix($change-time, $zone).gmt-offset;
$*TZ = $new-offset;
$supplier.emit:
ShiftInfo.new(olson-id => $zone.name, :$old-offset, :$new-offset, :$change-time)
}
react {
whenever timezone-shifts() -> $meta {
say "At {DateTime.new: $meta.change-time}, the GMT offset in {$meta.olson-id} "
~ "changed from {$meta.old-offset} to {meta.new.offset}";
}
}
@Xliff
Copy link

Xliff commented Oct 15, 2022

To add more flavor to your code, and to give you something that tests the mechanism, I've added the following, which gives you events for minute, hour, day, week, month and year.

Enjoy!

my %suppliers;
our %shifts is export;
my %times;

my $master = DateTime.now;

class TimeEvent {
  has $.time is built;
}

my $minute-time = $master;
for <minute hour day week month year> {
  %suppliers{$_} = Supplier::Preserving.new;
  %shifts{$_}    = -> { %suppliers{$_}.Supply };
  %times{$_}     =  $master;
  start loop {
    await Promise.at(
      Instant.from-posix: (
        %times{$_} = %times{$_}.later( |("{ $_ }" => 1) ).truncated-to($_)
      ).posix
    );

    %suppliers{$_}.emit: TimeEvent.new( time => %times{$_} );
  }
}

react {
  whenever %shifts<minute>() -> $e {
    CATCH { default { .message.say } }

    say "Minute shifted for event { $e.gist }";
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment