suncalc icon indicating copy to clipboard operation
suncalc copied to clipboard

It doesn't calculate correctly for other timezones relative to my own

Open oneuxco opened this issue 6 years ago • 12 comments

If I live in GMT-7 (DST), and look up New York coordinates, the times are all messed up.

I made a date variable that is specific for New York (or the location given by user) but the suncalc still screws up the timing...is there any fix for this?

Thanks!

oneuxco avatar May 20 '18 22:05 oneuxco

It seems like SunCalc will always calculate sun times in the local time zone. I managed to work around this issue with the following approach.

Where,

Given,

  • Location A is where the user is located (in time zone A)
  • Location B is where you want to calculate the sun times for in time zone B
const tzB = tzLookup(B.lat, b.lng)
const currentTimeAtB = DateTime.fromISO(new Date().toISOString(), { zone: tzB })
const suntimesAtB_in_tzA = SunCalc.getTimes(new Date(currentTimeAtB), B.lat, B.lng)

const sunriseAtB_in_tzB = DateTime.fromISO(suntimesAtB_in_tzA.sunrise.toISOString(), { zone: tzB })

andrewharvey avatar Dec 06 '18 05:12 andrewharvey

thanks men is working 👌

prepper25 avatar Jan 05 '19 03:01 prepper25

Also would like a fix for this. AWS machines are always set to UTC.

marrrrko avatar Jan 10 '19 03:01 marrrrko

@SrGrieves Does the workaround I posted work for you? I also blogged about it at https://tech.beyondtracks.com/posts/sun-times/

andrewharvey avatar Jan 10 '19 03:01 andrewharvey

@andrewharvey I'm working on an embedded system. Adding two additional external libraries is something I'd like to avoid. I like that SunCalc is small and self-sufficient.

marrrrko avatar Jan 10 '19 15:01 marrrrko

@andrewharvey I have tried your script and it seems to works but only if I edit "toJulian" function (with this ) isn't it?

ottopic avatar Feb 11 '19 07:02 ottopic

@ottopic I didn't do that, though my times could be a day off without it. I haven't done that detailed testing. If that's the case, good catch.

andrewharvey avatar Feb 11 '19 07:02 andrewharvey

It seems like SunCalc will always calculate sun times in the local time zone. I managed to work around this issue with the following approach.

Where,

Given,

  • Location A is where the user is located (in time zone A)
  • Location B is where you want to calculate the sun times for in time zone B
const tzB = tzLookup(B.lat, b.lng)
const currentTimeAtB = DateTime.fromISO(new Date().toISOString(), { zone: tzB })
const suntimesAtB_in_tzA = SunCalc.getTimes(new Date(currentTimeAtB), B.lat, B.lng)

const sunriseAtB_in_tzB = DateTime.fromISO(suntimesAtB_in_tzA.sunrise.toISOString(), { zone: tzB })

This saved me hours of figuring out how to do the transformation. Such a nice little library but in so many applications you have to operate with UTC times.

m3h0w avatar Jul 13 '20 16:07 m3h0w

For a personal project I ended up creating an NPM package of a modified suncalc to do this. It's called suncalc-tz, if anyone comes across this and is looking for something quick and dirty, might be worth a try. I wouldn't recommend it for production though, I haven't thoroughly tested it.

Similar to the code above, the package basically just pulls in a minified tzlookup to get the timezone and combines that with the Intl standard library:

  // Convert dates to the time at lat/lng
  for (let time in result) {
    const options = {timeZone: tz, year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric'};
    result[time] = new Date(Date.parse(new Intl.DateTimeFormat('default', options).format(result[time])));
  }

Christopher-Hayes avatar Nov 23 '20 11:11 Christopher-Hayes

For a personal project I ended up creating an NPM package of a modified suncalc to do this. It's called suncalc-tz, if anyone comes across this and is looking for something quick and dirty, might be worth a try. I wouldn't recommend it for production though, I haven't thoroughly tested it.

Similar to the code above, the package basically just pulls in a minified tzlookup to get the timezone and combines that with the Intl standard library:

  // Convert dates to the time at lat/lng
  for (let time in result) {
    const options = {timeZone: tz, year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric'};
    result[time] = new Date(Date.parse(new Intl.DateTimeFormat('default', options).format(result[time])));
  }

Found a minor issue - it crashes for high latitudes where some of the values are not available (for example, in summer there is no nautical dusk / dawn or night in Iceland). I think that the fix should be as easy as adding if ( !isNaN(result[time]) ) { ... } around the conversion, so I didn't bother with a pull request.

stephanmantler avatar May 03 '22 21:05 stephanmantler

This will probably not work for regions that implement day light saving?

const { sunrise } = getTimes(new Date(), lat, lon);
const tzOffset = sunrise.getTimezoneOffset();
console.log('Corrected time', new Date(sunrise.getTime() - tzOffset * 60000));

gwest7 avatar May 15 '22 17:05 gwest7

If you're only calling getPosition, you can pass in a UTC epoch int in milliseconds for the time, rather than a Date object, as the function only calls valueOf on that parameter.

aiden-jeffrey avatar Aug 22 '22 12:08 aiden-jeffrey