http://qs321.pair.com?node_id=1025613

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks!
I am trying to display the current tide based on the sample XML I have attached. Based on now's time changed to seconds against the times changed to seconds from the XML to show current tide, but I am missing something on the logic to show the current tide based on the time now. I hope I made it clear, here is the code I am using:
#!/usr/bin/perl use strict; use warnings; use XML::Simple; use Data::Dumper; use Time::Zone; use Date::Format; use Date::Parse; my ($today_datex, $today_time) = get_timezone(); my $today_date = "2013/03/27"; # using this to match XML attached belo +w my $now_in_seconds = str2time("$today_date $today_time"); print "\n $today_date, $today_time - Now in Seconds is: $now_in_second +s\n"; # 1364345520 # create object my $xml = new XML::Simple (KeyAttr=>[]); # read XML file my $data = $xml->XMLin("tides.xml"); my @time_in_seconds; foreach my $tides (@{$data->{data}->{item}}) { if($tides->{date} eq $today_date) { $tides->{highlow} =~ s/L/Low/; $tides->{highlow} =~ s/H/High/; my $format_date = "$tides->{date} $tides->{time}"; my $date_to_seconds = str2time($format_date); print " Test: ".$tides->{highlow}, " Tide at: ", $tides->{time}, +"\n"; push @time_in_seconds, $date_to_seconds; } } my $t1b = $time_in_seconds[0]; my $t2b = $time_in_seconds[1]; my $t3b = $time_in_seconds[2]; my $t4b = $time_in_seconds[3]; if( ($now_in_seconds >= $t1b) && ( $now_in_seconds < $t2b ) ) { print "\n Option 1\n"; }elsif( ($now_in_seconds >= $t2b) && ( $now_in_seconds < $t3b ) ) { print "\n Option 2\n"; }elsif( ($now_in_seconds >= $t3b ) && ( $now_in_seconds < $t4b ) ) { print "\n Option 3\n"; }elsif( $now_in_seconds >= $t4b ) { print "\n Option 4\n"; }else{ print "\n We have a problem!\n\n"; } sub get_timezone { $ENV{'TZ'} = 'America/New_York'; my $today_date = time2str( "%Y/%m/%d", time); # "%m-%d-%Y" my $today_time = time2str( "%I:%M %p", time); #"%H:%M:%S" return $today_date, $today_time; } =code <?xml version="1.0" encoding="ISO-8859-1" ?> <datainfo> <data> <item> <date>2013/03/27</date> <day>Wed</day> <time>12:21 AM</time> <predictions_in_ft>4.2</predictions_in_ft> <predictions_in_cm>128</predictions_in_cm> <highlow>H</highlow> </item> <item> <date>2013/03/27</date> <day>Wed</day> <time>06:20 AM</time> <predictions_in_ft>0.0</predictions_in_ft> <predictions_in_cm>0</predictions_in_cm> <highlow>L</highlow> </item> <item> <date>2013/03/27</date> <day>Wed</day> <time>12:50 PM</time> <predictions_in_ft>4.1</predictions_in_ft> <predictions_in_cm>125</predictions_in_cm> <highlow>H</highlow> </item> <item> <date>2013/03/27</date> <day>Wed</day> <time>06:39 PM</time> <predictions_in_ft>0.2</predictions_in_ft> <predictions_in_cm>6</predictions_in_cm> <highlow>L</highlow> </item> </data> </datainfo> =cut
Thanks for looking!

Replies are listed 'Best First'.
Re: Display tide based on time now.
by GrandFather (Saint) on Mar 27, 2013 at 02:40 UTC

    Works for me, or at least generates the following output which I guess is right:

    2013/03/27, 03:35 PM - Now in Seconds is: 1364351700 Test: High Tide at: 12:21 AM Test: Low Tide at: 06:20 AM Test: High Tide at: 12:50 PM Test: Low Tide at: 06:39 PM Option 3

    Note that I changed the file read line to:

    local $/; my $data = $xml->XMLin(<DATA>);

    and put the data in a __DATA__ block to save generating a file in addition to the script.

    True laziness is hard work
      The result I am expecting should only be one of "Test:" lines printed inside of the foreach based on the time range of now and the time form the XML. That is my issue!
      It works inside of the "foreach", but I would like to print the results outside of the "foreach" based on the time now, thats why I have the "IFs" below on the code.
Re: Display tide based on time now.
by hdb (Monsignor) on Mar 27, 2013 at 09:41 UTC

    This code will find the latest tide info before current time. Disclaimer: I cannot test the code as some missing modules resist installation on my box now.

    my $last_time = 0; my $current_tide = "We have a problem!"; foreach my $tides (@{$data->{data}->{item}}) { my $format_date = "$tides->{date} $tides->{time}"; my $date_to_seconds = str2time($format_date); if( $date_to_seconds > $last_time and $date_to_seconds < $now_in_s +econds ) { $tides->{highlow} =~ s/L/Low/; $tides->{highlow} =~ s/H/High/; $current_tide = " Test: ".$tides->{highlow}." Tide at: ".$tides->{ +time}; $last_time = $date_to_seconds; } } print "$current_tide\n";
      Unfortunately it does not work, it will not match any time before the first AM time, its back where my issue is.

        I might not be quite sure what you want to achieve. Can you please try this?

        my $last_time = 0; my $current_tide = "Now is before first tide in xml file."; foreach my $tides (@{$data->{data}->{item}}) { my $format_date = "$tides->{date} $tides->{time}"; my $date_to_seconds = str2time($format_date); if( $date_to_seconds > $last_time and $date_to_seconds <= $now_in_ +seconds ) { $tides->{highlow} =~ s/L/Low/; $tides->{highlow} =~ s/H/High/; $current_tide = " Test: ".$tides->{highlow}." Tide at: ".$tides->{ +time}; $last_time = $date_to_seconds; } } if( $now_in_seconds > $last_time ) { $current_tide = "Now is after the last tide in xml file." } print "$current_tide\n";
Re: Display tide based on time now.
by Krambambuli (Curate) on Mar 28, 2013 at 10:06 UTC
    Hi, with the following code replacing your main code,
    my @tides = ( { time_in_seconds => 0, high_low => 'Unknown', time => 'Unknown', } ); foreach my $tides (@{$data->{data}->{item}}) { if($tides->{date} eq $today_date) { $tides->{highlow} =~ s/L/Low/; $tides->{highlow} =~ s/H/High/; my $format_date = "$tides->{date} $tides->{time}"; my $date_to_seconds = str2time($format_date); #print " Test: ".$tides->{highlow}, " Tide at: ", $tides->{time}, + "\n"; $tides->{time_in_seconds} = $date_to_seconds; push @tides, $tides; } } push @tides, { time_in_seconds => $now_in_seconds + 10000000, highlow => 'Unknown', time => 'Unknown', }; my @future_tides = grep { $_->{time_in_seconds} >= $now_in_seconds } @ +tides; my @past_tides = grep { $_->{time_in_seconds} < $now_in_seconds } @ +tides; my $next_tide = $future_tides[0]; my $previous_tide = $past_tides[ -1]; print "Next tide: ", $next_tide->{highlow}, " Tide at: ", $next_tide-> +{time}, "\n"; print "iPrevious tide: ", $previous_tide->{highlow}, " Tide at: ", $pr +evious_tide->{time}, "\n"; exit;
    I get

    2013/03/27, 06:05 AM - Now in Seconds is: 1364378700 Next tide: Low Tide at: 06:20 AM Previous tide: High Tide at: 12:21 AM
    which might be close to what you wish. UPDATE Updated code to display something whatever the 'now' time is.
      Yes it is close, but this is how your code stands:

      First tide time on 2013/03/27 - 12:21 AM - The current time has to be 12:22 AM to work.
      Last tide time on 2013/03/27 - 06:39 PM - The current time can not be over that.

      It only works OK if its one minute after the time of the first tide time and not over the time of the last tide time.

      Thanks for trying!
        Check the updated code, if you wish. It should display something for whatever 'now' time.