Solar local time

i'm working on a sticky issue: i'm converting some times based on a utc time
and longitude - the goal is the express the time as solar local time.

the code i have is close. it does something like:

     DEG_PER_HR = 15.0
     SECS_PER_MIN = 60.0
     SECS_PER_HR = SECS_PER_MIN * 60.0
     SECS_PER_DAY = SECS_PER_HR * 24

     # longitudes > 180 degrees are behind UT
     # longitudes <= 180 degrees are ahead of UT

     offset_seconds =
       if longitude > 180.0
         - ((360.0 - longitude) / DEG_PER_HR) * SECS_PER_HR
       else
         (longitude / DEG_PER_HR) * SECS_PER_HR
       end

     utc + offset_seconds

this in fact yields the correct time __except__ that's it's expressed in zulu
time and not the 'local' time zone. the trick is that 'local' here means
'there' not 'here'! :wink: in otherwords it needs to be expressed in the local
time zone of that __longitude__ not mine and not that of greenwich.

to put it more consisely i need to be able to follow

   locatime_but_in_utc = utc + offset_seconds

with

   move_to_zone locatime_but_in_utc, longitude

or some other viable alternative.

thoughts?

-a

···

--
to foster inner awareness, introspection, and reasoning is more efficient than
meditation and prayer.
- h.h. the 14th dali lama

i'm working on a sticky issue: i'm converting some times based on a utc time
and longitude - the goal is the express the time as solar local time.

the code i have is close. it does something like:

    DEG_PER_HR = 15.0
    SECS_PER_MIN = 60.0
    SECS_PER_HR = SECS_PER_MIN * 60.0
    SECS_PER_DAY = SECS_PER_HR * 24

    # longitudes > 180 degrees are behind UT
    # longitudes <= 180 degrees are ahead of UT

    offset_seconds =
      if longitude > 180.0
        - ((360.0 - longitude) / DEG_PER_HR) * SECS_PER_HR
      else
        (longitude / DEG_PER_HR) * SECS_PER_HR
      end

    utc + offset_seconds

this in fact yields the correct time __except__ that's it's expressed in zulu
time and not the 'local' time zone. the trick is that 'local' here means
'there' not 'here'! :wink: in otherwords it needs to be expressed in the local
time zone of that __longitude__ not mine and not that of greenwich.

to put it more consisely i need to be able to follow

  locatime_but_in_utc = utc + offset_seconds

with

  move_to_zone locatime_but_in_utc, longitude

or some other viable alternative.

thoughts?

Does TZInfo bring you closer?
Stolen from the README:

···

On Aug 8, 2006, at 2:23 PM, ara.t.howard@noaa.gov wrote:

Example usage

To convert a time in UTC to a local time in the America/New_York timezone, you can do the following:

  require_gem 'tzinfo'
  include TZInfo

  tz = Timezone.get('America/New_York')
  local = tz.utc_to_local(Time.utc(2005,8,29,15,35,0))

Note that the Time returned will look like it is UTC (Time.zone will return "UTC"). This is because it is not currently possible to change the offset of an individual Time instance.

-a
--
to foster inner awareness, introspection, and reasoning is more efficient than
meditation and prayer.
- h.h. the 14th dali lama

yeah - the thing is that this 'localtime' will be in utc :wink:

-a

···

On Tue, 8 Aug 2006, Jan Svitok wrote:

Once more: what you want to achive is have function

local_solar_time(utc_time, longitude)

This is my (maybe naive) approach (It's possible I'm missing something)
To me it seems that your calculation is right,

local_solar_time = utc_time +/- offset_seconds(longitude)

+/- depends on whether longitude grows to the west (then -) or east (+)

if you want have it in local time zone, then it would be

localtime = utc_time + timezone_offset(longitude, latitude) obviously.

--
to foster inner awareness, introspection, and reasoning is more efficient than
meditation and prayer.
- h.h. the 14th dali lama

ZONES = class << Time; ZoneOffset.keys.map {|x| x.length == 1 ? x :
nil}.compact.sort; end
ZONES.unshift ZONES.pop

def move_to_zone( utc, longitude )
  zone = ZONES[Integer(longitude) / Integer(DEG_PER_HR)]
  utc - Time.zone_offset(zone)
end

This does not take into account daylight savings, etc. But give it a
shot and see if it's what you need.

TwP

···

On 8/8/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:

i'm working on a sticky issue: i'm converting some times based on a utc time
and longitude - the goal is the express the time as solar local time.

the code i have is close. it does something like:

     DEG_PER_HR = 15.0
     SECS_PER_MIN = 60.0
     SECS_PER_HR = SECS_PER_MIN * 60.0
     SECS_PER_DAY = SECS_PER_HR * 24

     # longitudes > 180 degrees are behind UT
     # longitudes <= 180 degrees are ahead of UT

     offset_seconds =
       if longitude > 180.0
         - ((360.0 - longitude) / DEG_PER_HR) * SECS_PER_HR
       else
         (longitude / DEG_PER_HR) * SECS_PER_HR
       end

     utc + offset_seconds

this in fact yields the correct time __except__ that's it's expressed in zulu
time and not the 'local' time zone. the trick is that 'local' here means
'there' not 'here'! :wink: in otherwords it needs to be expressed in the local
time zone of that __longitude__ not mine and not that of greenwich.

to put it more consisely i need to be able to follow

   locatime_but_in_utc = utc + offset_seconds

with

   move_to_zone locatime_but_in_utc, longitude

or some other viable alternative.

thoughts?

snip

this in fact yields the correct time __except__ that's it's expressed in zulu
time and not the 'local' time zone. the trick is that 'local' here means
'there' not 'here'! :wink: in otherwords it needs to be expressed in the local
time zone of that __longitude__ not mine and not that of greenwich.

to put it more consisely i need to be able to follow

   locatime_but_in_utc = utc + offset_seconds

with

   move_to_zone locatime_but_in_utc, longitude

Clarification question ... do you want the returned value to be a
Float or an actual Time object?

TwP

PS Maybe I should have asked this before posting my little solution there :confused:

···

On 8/8/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:

If I understand the problem you describe (likelihood estimate ~ 50%), it's similar to a telemetry data problem I once worked on. Here is how I handled it:

1. express the local solar time value of interest in seconds from local midnight
2. convert the UTC time stamp to seconds from UTC midnight
3. longitude shift the result of 2 to the local time frame
4. compare result of 1 and 3 to determine whether or not to process further

Maybe you could adopt a similar approach.

Regards, Morton

···

On Aug 8, 2006, at 2:23 PM, ara.t.howard@noaa.gov wrote:

i'm working on a sticky issue: i'm converting some times based on a utc time
and longitude - the goal is the express the time as solar local time.

the code i have is close. it does something like:

    DEG_PER_HR = 15.0
    SECS_PER_MIN = 60.0
    SECS_PER_HR = SECS_PER_MIN * 60.0
    SECS_PER_DAY = SECS_PER_HR * 24

    # longitudes > 180 degrees are behind UT
    # longitudes <= 180 degrees are ahead of UT

    offset_seconds =
      if longitude > 180.0
        - ((360.0 - longitude) / DEG_PER_HR) * SECS_PER_HR
      else
        (longitude / DEG_PER_HR) * SECS_PER_HR
      end

    utc + offset_seconds

this in fact yields the correct time __except__ that's it's expressed in zulu
time and not the 'local' time zone. the trick is that 'local' here means
'there' not 'here'! :wink: in otherwords it needs to be expressed in the local
time zone of that __longitude__ not mine and not that of greenwich.

to put it more consisely i need to be able to follow

  locatime_but_in_utc = utc + offset_seconds

with

  move_to_zone locatime_but_in_utc, longitude

or some other viable alternative.

thoughts?

-a
--
to foster inner awareness, introspection, and reasoning is more efficient than
meditation and prayer.
- h.h. the 14th dali lama

nope. timezones are politicalized solar local times. basically i'm searching
a polar orbiting satellite data set for scanlines where the localtime is about
7 am. it sounds easy - it's near impossible.

-a

···

On Wed, 9 Aug 2006, Logan Capaldo wrote:

Does TZInfo bring you closer?
Stolen from the README:

Example usage

To convert a time in UTC to a local time in the America/New_York timezone, you can do the following:

  require_gem 'tzinfo'
  include TZInfo

  tz = Timezone.get('America/New_York')
  local = tz.utc_to_local(Time.utc(2005,8,29,15,35,0))

Note that the Time returned will look like it is UTC (Time.zone will return "UTC"). This is because it is not currently possible to change the offset of an individual Time instance.

--
to foster inner awareness, introspection, and reasoning is more efficient than
meditation and prayer.
- h.h. the 14th dali lama

it's close, but check this out:

     harp:~ > cat a.rb
     require 'time'

     class Time
       ZONES =
         class << self
           (_ = ZoneOffset.keys.select{|z| z.size == 1}.sort).unshift(_.pop)
         end
       def translated longitude
         zone = ZONES[Integer(longitude) / 15]
         utc - Time.zone_offset(zone)
       end
     end

     t = Time.parse('1999-12-31T23:59:59Z') or 'party like it is'

     require 'yaml'

     [0, 15, 16, 30, 31].each do |degrees|
       y degrees => t.translated(degrees).iso8601

       y -degrees => t.translated(-degrees).iso8601
     end

     harp:~ > ruby a.rb
     0: "1999-12-31T23:59:59Z"
     15: "1999-12-31T22:59:59Z"
     -15: "2000-01-01T11:59:59Z"
     16: "1999-12-31T22:59:59Z"
     -16: "2000-01-01T10:59:59Z"
     30: "1999-12-31T21:59:59Z"
     -30: "2000-01-01T10:59:59Z"
     31: "1999-12-31T21:59:59Z"
     -31: "2000-01-01T09:59:59Z"

take one example

     15: "1999-12-31T22:59:59Z"

the time is correct but the zone is not. consider, 15 degrees to the east of 0
longitude at '1999-12-31T23:59:59Z' the solar local time is

     '1999-12-31T22:59:59+01:00'

make sense?

-a

···

On Wed, 9 Aug 2006, Tim Pease wrote:

ZONES = class << Time; ZoneOffset.keys.map {|x| x.length == 1 ? x :
nil}.compact.sort; end
ZONES.unshift ZONES.pop

def move_to_zone( utc, longitude )
zone = ZONES[Integer(longitude) / Integer(DEG_PER_HR)]
utc - Time.zone_offset(zone)
end

This does not take into account daylight savings, etc. But give it a
shot and see if it's what you need.

--
to foster inner awareness, introspection, and reasoning is more efficient than
meditation and prayer.
- h.h. the 14th dali lama

i'm starting to think it has to be a float... but a time would be better.

-a

···

On Wed, 9 Aug 2006, Tim Pease wrote:

Clarification question ... do you want the returned value to be a
Float or an actual Time object?

TwP

PS Maybe I should have asked this before posting my little solution there :confused:

--
to foster inner awareness, introspection, and reasoning is more efficient than
meditation and prayer.
- h.h. the 14th dali lama

yes. i'm thinking of something similar - perhaps returning a fraction (of the
current day) or something similar. the reason i was trying to stick with time
objects is to make calculations easier...

it's damn tricky though.

-a

···

On Wed, 9 Aug 2006, Morton Goldberg wrote:

If I understand the problem you describe (likelihood estimate ~ 50%), it's similar to a telemetry data problem I once worked on. Here is how I handled it:

1. express the local solar time value of interest in seconds from local midnight
2. convert the UTC time stamp to seconds from UTC midnight
3. longitude shift the result of 2 to the local time frame
4. compare result of 1 and 3 to determine whether or not to process further

--
to foster inner awareness, introspection, and reasoning is more efficient than
meditation and prayer.
- h.h. the 14th dali lama

too funny. this is a sketch of my code so far:

     off_sec =
       if longitude > 180.0
         ((360.0 - longitude) / DEG_PER_HR) * SECS_PER_HR
       else
         (longitude / DEG_PER_HR) * SECS_PER_HR
       end

     signedness = off_sec > 0 ? +1 : -1
     sign = signedness > 0 ? '+' : '-'

     hour_offset, r = off_sec.to_i.abs.divmod SECS_PER_HR
     min_offset, r = r.divmod SECS_PER_MIN

     hour_offset *= signedness

     zone = '%s%-02.2d:%-02.2d' % [sign, hour_offset.to_i, min_offset.to_i.abs]

     utc_plus_off = time + off_sec

     localtime_expressed_in_utc = Time.parse(utc_plus_off.sub(%r/Z$/, zone)).utc

look familiar :wink:

yeah - this will do it - the time is expressed in utc but at least it's the
actual correct time with respect the ground sampled by the bird at that moment.

thanks for the help - the fact that you came up with that independently makes
me feel better.

-a

···

On Tue, 8 Aug 2006, Tim Pease wrote:

That does make sense. Here's what I came up with based on that ...

class Time

OFFSETS = class << self; ZoneOffset end
ZONES = OFFSETS.keys.select {|z| z.length == 1}.sort
ZONES.unshift ZONES.pop

def translate longitude
  zone = ZONES[Integer(longitude) / 15]
  t = utc - ::Time.zone_offset(zone)

  unless zone == 'Z'
    zone = OFFSETS[zone]
    str = t.iso8601

    str.sub! %r/Z$/, ''
    str << (zone > 0 ? '-' : '+')
    str << "%02d:00" % zone.abs

    t = Time.iso8601 str
  end

  return t
end

I had to go through and intermediary string in order to get into the
right timezone. Printing out the returned Time object says it is
still in UTC, but that doesn't matter. It's in the correct timezone
for your parsing needs.

If that doesn't work or is not what you want, just shot me a private
e-mail with your work number and I'll cal you

--
to foster inner awareness, introspection, and reasoning is more efficient than
meditation and prayer.
- h.h. the 14th dali lama

I'm not sure I understand what you are trying to do. Are you trying to work out a time-zone by using longitude? Surely not...

Cheers,
Bob

···

On Aug 8, 2006, at 6:42 PM, Ara.T.Howard wrote:

On Tue, 8 Aug 2006, Tim Pease wrote:

That does make sense. Here's what I came up with based on that ...

class Time

OFFSETS = class << self; ZoneOffset end
ZONES = OFFSETS.keys.select {|z| z.length == 1}.sort
ZONES.unshift ZONES.pop

def translate longitude
  zone = ZONES[Integer(longitude) / 15]
  t = utc - ::Time.zone_offset(zone)

  unless zone == 'Z'
    zone = OFFSETS[zone]
    str = t.iso8601

    str.sub! %r/Z$/, ''
    str << (zone > 0 ? '-' : '+')
    str << "%02d:00" % zone.abs

    t = Time.iso8601 str
  end

  return t
end

I had to go through and intermediary string in order to get into the
right timezone. Printing out the returned Time object says it is
still in UTC, but that doesn't matter. It's in the correct timezone
for your parsing needs.

If that doesn't work or is not what you want, just shot me a private
e-mail with your work number and I'll cal you

too funny. this is a sketch of my code so far:

    off_sec =
      if longitude > 180.0
        ((360.0 - longitude) / DEG_PER_HR) * SECS_PER_HR
      else
        (longitude / DEG_PER_HR) * SECS_PER_HR
      end

    signedness = off_sec > 0 ? +1 : -1
    sign = signedness > 0 ? '+' : '-'

    hour_offset, r = off_sec.to_i.abs.divmod SECS_PER_HR
    min_offset, r = r.divmod SECS_PER_MIN

    hour_offset *= signedness

    zone = '%s%-02.2d:%-02.2d' % [sign, hour_offset.to_i, min_offset.to_i.abs]

    utc_plus_off = time + off_sec

    localtime_expressed_in_utc = Time.parse(utc_plus_off.sub(%r/Z$/, zone)).utc

look familiar :wink:

yeah - this will do it - the time is expressed in utc but at least it's the
actual correct time with respect the ground sampled by the bird at that moment.

thanks for the help - the fact that you came up with that independently makes
me feel better.

-a
--
to foster inner awareness, introspection, and reasoning is more efficient than
meditation and prayer.
- h.h. the 14th dali lama

----
Bob Hutchison -- blogs at <http://www.recursive.ca/hutch/&gt;
Recursive Design Inc. -- <http://www.recursive.ca/&gt;
Raconteur -- <http://www.raconteur.info/&gt;
xampl for Ruby -- <http://rubyforge.org/projects/xampl/&gt;

<snip my own broken code>

for anyone following the thread or searching archvies here's the answer i ended
up with, it's correct afaik:

     harp:~ > cat a.rb
     require 'date'
     require 'time'

···

On Wed, 9 Aug 2006, Ara.T.Howard wrote:

too funny. this is a sketch of my code so far:

     #
     # returns a datetime object defined at a certain location on earth. in
     # otherwords a certian time 'there' not 'here' or 'utc' - a time in an
     # arbitrary other timezone.
     #
       def solar_localtime time, longitude
         deg_per_hr = 15
         secs_per_hr = 60 * 60
         longitude = Float longitude

         t =
           case time
             when Time
               time.utc
             when DateTime
               Time.parse time.to_s
             else
               Time.parse time.to_s
           end

         if longitude > 180.0
           off_sec = - ((360.0 - longitude) / deg_per_hr) * secs_per_hr
           tz = - ((360.0 - longitude) ) / 360.0
         else
           off_sec = (longitude / deg_per_hr) * secs_per_hr
           tz = (longitude ) / 360.0
         end

         t += off_sec

         y, d, h, m, s = %w( year yday hour min sec ).map{|m| t.send m}

         DateTime.ordinal y, d, h, m, s, tz
       end
     #
     # demo
     #
       now = Time.now.utc # you could also do: now = DateTime.now
       puts(now.iso8601)

       require 'yaml'
       [15, 30, 45].each do |longitude|
         y longitude => solar_localtime(now, longitude).to_s
         y -longitude => solar_localtime(now, -longitude).to_s
       end

     harp:~ > ruby a.rb
     2006-08-09T21:06:33Z
     15: 2006-08-09T22:06:32+0100
     -15: 2006-08-09T20:06:33-0100
     30: 2006-08-09T23:06:33+0200
     -30: 2006-08-09T19:06:32-0200
     45: 2006-08-10T00:06:33+0300
     -45: 2006-08-09T18:06:33-0300

the trick is use DateTime - you can't do it with Time.

regards.

-a
--
to foster inner awareness, introspection, and reasoning is more efficient than
meditation and prayer.
- h.h. the 14th dali lama

yes. not __political__ timezone - actual timezone. each 15 degrees of lon is
exactly one hour so it's easy.

-a

···

On Wed, 9 Aug 2006, Bob Hutchison wrote:

I'm not sure I understand what you are trying to do. Are you trying to work out a time-zone by using longitude? Surely not...

--
to foster inner awareness, introspection, and reasoning is more efficient than
meditation and prayer.
- h.h. the 14th dali lama