#!/usr/bin/env perl use strict; use warnings; use DateTime::Format::Strptime; #use DateTime; use REST::Client; use Data::Roundtrip qw/:all/; my $lat = 31; my $long = 80; # this is our fetcher, similar to LWP::UserAgent # but better suited for this kind of web service: REST my $rest = REST::Client->new() or die "failed to construct client"; # see examples in # https://www.weather.gov/documentation/services-web-api # set the host $rest->setHost('https://api.weather.gov'); # and this is our query with lat,long specified above my $query = "/gridpoints/TOP/$lat,$long/forecast"; # make the request and check the response code, 200 is good my $response = $rest->GET($query) or die "failed to GET($query)"; if( $rest->responseCode() != 200 ){ die "failed to GET(".$rest->getHost()."/$query) with ".$rest->responseCode() } # we get back JSON my $jsonstr = $response->responseContent(); # convert JSON string to a perl variable my $pv = json2perl($jsonstr); if( ! defined $pv ){ die "something wrong with this alleged json : '$jsonstr'" } # go to the interesting part my $forecasts = $pv->{'properties'}->{'periods'}; # or print it all and examine it # print perl2dump($pv); # we have some dates in the data in ISO8601 format # this is a parser to convert that date to a DateTime # object which we can query about things (like seconds-unix-epoch) my $dateparser = DateTime::Format::Strptime->new( # parses 2020-04-26T06:00:00-05:00, # %F then literal T then %T then timezone offset pattern => '%FT%T%z' ) or die "failed to DateTime::Format::Strptime->new()"; # we store each prediction in this hash, keyed on start-end dates # see below $key my %parsed; for my $aforecast (@$forecasts){ print "go: ".$aforecast->{'name'}."\n"; # extract various things from 1 prediction record # examine the record like : print perl2dump($aforecast); # like "This Afternoon" my $period_str = $aforecast->{'name'}; # start and end times of the prediction, convert them to objects my $start_time_str = $aforecast->{'startTime'}; my $start_time_dateobj = $dateparser->parse_datetime($start_time_str) or die "parsing date '$start_time_str'."; my $end_time_str = $aforecast->{'endTime'}; my $end_time_dateobj = $dateparser->parse_datetime($end_time_str) or die "parsing date '$start_time_str'."; # sunny? my $forecast_str = $aforecast->{'shortForecast'}; # temperature as a number, see later for the units my $temp = $aforecast->{'temperature'}; # store this record/prediction in our %parsed hash # keyed on this: my $key = $start_time_str." to ".$end_time_str; $parsed{$key} = { 'date-human-str' => $period_str, # edit: added this 'date-from' => $start_time_str, 'date-to' => $end_time_str, 'date-span-hours' => ($end_time_dateobj->epoch()-$start_time_dateobj->epoch())/3600, 'date-from-epoch' => $start_time_dateobj->epoch(), 'date-to-epoch' => $end_time_dateobj->epoch(), 'forecast-string' => $forecast_str, # we append temp unit to the key, e.g. 'F' 'forecast-temp-'.$aforecast->{'temperatureUnit'} => $temp, } } print perl2dump(\%parsed);