solar local time

A

ara.t.howard

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'! ;-) 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
 
L

Logan Capaldo

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'! ;-) 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:
 
A

Ara.T.Howard

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.

yeah - the thing is that this 'localtime' will be in utc ;-)

-a
 
A

ara.t.howard

Does TZInfo bring you closer?
Stolen from the README:

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
 
T

Tim Pease

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'! ;-) 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?

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
 
T

Tim Pease

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'! ;-) 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 :/
 
A

ara.t.howard

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.

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"
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
 
A

ara.t.howard

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 :/

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

-a
 
M

Morton Goldberg

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
 
A

ara.t.howard

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

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
 
A

Ara.T.Howard

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
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 ;-)

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
 
B

Bob Hutchison

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

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
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 ;-)

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/>
Recursive Design Inc. -- <http://www.recursive.ca/>
Raconteur -- <http://www.raconteur.info/>
xampl for Ruby -- <http://rubyforge.org/projects/xampl/>
 
A

ara.t.howard

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...

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

-a
 
A

ara.t.howard

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

<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'
#
# 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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,209
Messages
2,571,088
Members
47,687
Latest member
IngridXxj

Latest Threads

Top