So, I'm working a project with the Amazon Echo. My goal is to record when I did a specific action and to record it into a DB. My issue is timezones, and I avoid this by using epoch time. However, from what I can tell of custom slots for an intent, my choices are formatted date strings with no time, or formatted time strings with no dates, and on top of all of that, I have no way of grabbing the client's timezone without specifically asking for it based on some forum posts I found with my google fu.
Does the echo just hate dates? This seems like something that should be really easy, but I'm struggling to figure out how to go about it without being really awkward and asking where they live so I can do a lookup of their timezone. I already had to make a pivot from telling them the specific time they did something to how long ago they did something because I can't pass dates back to the Echo and expect it to translate it. Is this another silly pivot I have to make?
Correct, you cannot get the client's TZ or location from Alexa. It's a privacy issue. The only way is to ask for it yourself.
There is a custom slot for "five digit number" which is perfect for ZIP code. That is the simplest way to get a user's approximate location.
If you want to get more inventive, since the Echo is (pretty much) only used in America, you only have to narrow it down to one of four time zones. (At the expense of Alaska, Hawaii and Arizona for half the year.) You could just ask which timezone they are in, which is less intrusive.
Or, if you want to get creative, make a joke out of it.
A: "Pop quiz: Are you in Eastern Standard time?"
U: "No"
A: "Drat. Let me guess again. You seem like a Mountain Time person."
...
Yes. It is an irritating limitation. But if you can find a novel way to work around it your skill will be more endearing.
It looks like you cannot (yet) detect the user's timezone, but you should still be able to achieve your goals. A few thoughts:
You could just make the system ignorant of timezones altogether. Each user may have a different timezone, but all times for a particular user will be in the same timezone so any duration calculations will work fine.
There is no DATETIME slot type, so you need to handle each slot separately as AMAZON.DATE and AMAZON.TIME. e.g. "Mark completion on {DATE} at {TIME}"
Also, if you are real-world marking completion datetime, can you just generate the timestamp inside your code, rather than making them say it?
Requesting Zip could be a quick way to set timezone, if necessary.
Hacky: If you use Account Linking you may be able to detect their timezone from the client-side on your login page.
Converting between server timetamp and spoken times in the user's timezone will be problematic, but perhaps you can work around it until amazon includes timezone data.
There is a way to find the user's timezone from country code and postal code which Amazon provides. You just need to enable the permission in the developer's console.
After that, whenever you receive a request from Alexa voice service, you will get a consent token. Which indicates that the user has given the permission.
You can then get the timezone of the user by querying Google API. The python code for the same is mentioned below.
# to get the country code and postal code of user
res = requests.get('{0}/v1/devices/{1}/settings/address/countryAndPostalCode'.format(context.System.apiEndpoint, context.System.device.deviceId),
headers = {'Authorization':'Bearer {}'.format(context.System.apiAccessToken)}).json()
postCode = res['postalCode']
countryCode = res['countryCode']
# key specific to the user
apiAccessKey = 'your-api-key'
# Google Geocoding API: provides latitude and longitude from country code and postal code
res = requests.get('https://maps.googleapis.com/maps/api/geocode/json?address={0},{1}&key={2}'
.format(countryCode, postCode, apiAccessKey)).json()
lat = res['results'][0]['geometry']['location']['lat']
lng = res['results'][0]['geometry']['location']['lng']
# Google's Time Zone API: provides timezone from latitude and longitude.
res = requests.get('https://maps.googleapis.com/maps/api/timezone/json?location={0},{1}×tamp={2}&key={3}'
.format(lat, lng, datetime.datetime.timestamp(datetime.datetime.now()),apiAccessKey)).json()
timezone = res['timeZoneId']
Related
I am creating a node app with mongo and trying to store createdOn field. I have two options, either go with the ISO date format("YYYY-MMM-DDThh:mm:ss.zzz") or use timestamp. My users will be mostly in India but my server is in Oregon USA, and all computation will be done over there. Just wanted your thoughts on which one to use and why?Could not find a nice blog post searching this. I hope the smart people who have already done this would help a fellow newbie out.
What am I already doing?
I am saving the date in the date time format,using momentTimeZone by Asia/Kolkata time and extracting it out. It's very painful and I have to remember that every time I write anything related to date I have to first convert it into IST and then proceed with any ops. Hence require your suggestion, whether to continue like this or try timestamp approach
After allowing the user to select their timezone many applications ask if the DST adjustment should be made. Given resources like the tz database which contain past and present information on DST observances for each timezone, why do applications ask?
They shouldn't. Usually those that do are not using the tz database and have made invalid assumptions about how time zones work.
It is usually paired with a time zone selection dropdown that only lists numeric offsets, like this:
One should instead consider asking for time zone like this:
By asking for countries first, one can reduce the choice of time zones from the tz database to just a handful for the country. And since many countries only have a single time zone, sometimes the user will just need to select their country.
BTW - Both of the above graphics are from the Pluralsight course, Date and Time Fundamentals, of which I am the author. I cover this issue, and many other similar common mistakes.
You can also read more in the timezone tag wiki, in the section titled "TimeZone != Offset".
There is one common exception to this rule - Microsoft Windows. If the chosen time zone has DST, then Microsoft allows a user the option to disable it:
This is sometimes needed because there are places in the world that are not represented fully by the options Windows presents. Microsoft doesn't use the TZ database for this, but has their own time zones that they maintain.
For example, if you live in Atikokan, Ontario, Canda, the only valid selection in Windows is Eastern Time with DST disabled. Compare that with the TZ database, which has defined a zone specifically as "America/Atikokan".
This can create a problem for .NET developers, as TimeZoneInfo.Local.Id will return "Eastern Standard Time" regardless of whether the DST flag is turned on or off in the control panel. However, if it's disabled, then all of the adjustment rules will have been stripped away. In other words, TimeZoneInfo.Local != TimeZoneInfo.FindBySystemId(TimeZoneInfo.Local.Id). If the application just stores the ID, then it has no way to retrieve the time zone for somewhere like Atikokan.
I've read many a post here re: GWT date handling.
One in particular that struck a cord with me was this one
Sending a date and timezone from GAE server to GWT client
Anyhow, there's a need on a project I'm working on to be able to display days, hours, minute intervals as labels in a grid. My team has adopted an approach where all date/time instances are passed the client from the server in ISO8601 String format. The server time zone is to be respected by the client. The biz use case is that all date/time instances are in "market time", so that any browser that visits the app will see and work with dates in the "market time" timezone which happens to be GMT-05:00 (if Daylight Savings in effect) or GMT-06:00 (if Standard Time in effect).
I have posted some source on Github, here:
https://github.com/fastnsilver/gwt-datehandling-example
Particularly...
https://github.com/fastnsilver/gwt-datehandling-example/blob/master/src/main/java/me/fns/gwt/datehandling/client/util/CSTimeUtil.java
and the GWTTestCase
https://github.com/fastnsilver/gwt-datehandling-example/blob/master/src/test/java/me/fns/gwt/datehandling/client/util/CSTimeUtilTestGwt.java
in the hopes that someone can stare at the utility (and test) we're employing for date handling and help us see what we're not seeing.
EDIT
The basic problem is that CSTimeUtil#hoursInDay(Date) is not being calculated correctly in Production mode for "transition days" This method is used by other methods (like CSTimeUtil#dateToHour(Date) and CSTimeUtil#labelsForDay(Date)).
I have deployed our application with the current implementation of CSTimeUtil and it appears to work, but not quite. I'm really confused by alternate test results when e.g., mvn gwt:test is run in GWT Mode or Production Mode on Windows where the OS timezone is set to various timezones other than U.S. GMT-05:00 or GMT-06:00.
Based on some hints from Andrei and some serious blood, sweat and tears, I figured this out on my own. I have updated the code in Github, so if you're curious please go have a look there.
The basics:
Make sure all Strings are ISO8601 (no millis) compliant when sent from server to client and vice versa
Use DateTimeFormat.getFormat("yyyy-MM-ddTHH:mm:ss.SZZZZ") to format and parse dates
Retreive GMT-prefixed time zone info from java.util.Date in "Market time" using DateTimeFormat(Date, TimeZone), where TimeZone param is set as TimeZone.createTimeZone(TZ_CONSTANTS_INSTANCE.americaChicago()) and time zone String retrieved by TimeZone.getISOTimeZoneString(Date)
Generating days, see generateDay(Date, int) or hours generateHour(Date, int), from a source date had to take into consideration that an increment or decrement coudl trigger a change in time zone offset if occurring on a "transition day".
If you time zone is fixed, why would you use a string to represent date/time? You can send a standard Java Date object to the client. If you want, you can even store all dates and times as Longs and pass Longs only. You also send the GWT's TimeZone Json string for your time zone (once per session). You can find it in the GWT - there is a file with strings for all time zones.
On a client you use DateTimeFormat with many predefined formats to display whatever you need: full date, month and date, date and time, etc. Just remember to create TimeZone object from this Json string and use it in DateTimeFormat.getFormat(...).format(Date, TimeZone).
With this approach you don't have to worry about DST changes (they are encoded in that Json string) and locales. You only pass simple Date or Long objects.
I can get a list of time zones with [NSTimeZone knownTimeZoneNames], but that only gives the time zone IDs which include one or two cities in each time zone.
The Date & Time settings has a great list of cities and I have seen a few other apps that have the same if not similar lookup lists.
Where do these lists come from?
I do need to relate a picked city to its time zone like Date & Time does.
Only 2? On 3.1 the [NSTimeZone knownTimeZoneNames] returns an array of 401 elements, and there are much less than 200 timezones on the Earth.
I'm pretty sure "other apps" use +knownTimeZoneNames as well, since this is the only public method returning such list. Please make sure your code is correct, though.
Settings.app uses the private CPCity API from the private AppSupport.framework. It does have San Francisco, but it's private.
You need to create your own database (the data can be copied from /System/Library/PrivateFrameworks/AppSupport.framework/all_cities_adj.plist).
What you are asking for is commonly referred to as the Olson database. See for instance this Wikipedia page. The public domain Zone.tab file contains all of the timezones. You can find a zones.tab file in the zoneinfo directory of the libical distribution.
I know it might be a late answer, but just in case someone else stumbles on it like I did the other day. I just open sourced a library that does exactly this. It is available as a CocoaPod and you can find it here:
https://github.com/gligorkot/TimeZonePicker
Also, thanks for all the replies above, they helped me in finding the correct cities database that is used for the Settings app.
I'm using GWT on the client (browser) and Joda Time on the server. I'd like to perform some DB lookups bounded by the day (i.e. 00:00:00 until 23:59:59) that a request comes in, with the time boundaries based on the user's (i.e. browser) timezone.
So I have the GWT code do a new java.util.Date() to get the time of the request, and send that to the server. Then I use Joda Time like so:
new DateTime(clientDate).toDateMidnight().toDateTime()
The trouble of course is that toDateMidnight(), in the absence of a specified TimeZone, will use the system's (i.e. the server's) TimeZone. I've been trying to find a simple way to pass the TimeZone from the browser to the server without much luck. In GWT I can get the GMT offset with:
DateTimeFormat.getFormat("Z").fmt(new Date())
which results in something like "-0400". But Joda Time's DateTimeZone.forID() wants strings formatted like "America/New_York", or an integer argument of hours and minutes. Of course I can parse "-0400" into -4 hours and 0 minutes, but I'm wondering if there is not a more straightforward way of doing this.
You could use java.util.Date's getTimezoneOffset() method. It's deprecated, but that's pretty usual for Date handling in GWT currently.
And AFAIR, you can specify something similar to "UTC+4" in Joda time.
Update: I looked it up, and it's "+04:00". Or use DateTimeZone.forOffsetHours() or even forOffsetMillis().
Gwittir (http://www.gwtsite.com) is a library for GWT that includes many cool utilities, like databinding, animation, reflection, and more. However, there are some other interesting goodies as well like the new Joda Time integration. If you have ever been frustrated by GWT’s lack of java.util.Calendar support, you’ll love this, as it makes it easy to do date manipulations in your applications.
otherwise, there are other ways to get timezone offset with + & -.
import java.util.TimeZone;
use: TimeZone.getDefault().getRawOffset()
this function will return the offset time in millisecond about your phone seeting. For Example, GMT-04:00 is equals to (-4)*60*60*1000 = -14400000.
After some operations to get the number which you want.
I have a similar but slightly different problem I think.
I actually need to store the clients timezone on the server, so that I can send out messages about dates stored in their calendar.
The dates are stored in UTC time in google app engine and of course I can store the current Timezone offset when creating the appointment. The problem comes when for instance I want to send out a summary email with a list of upcoming appointments in it. These appointments need to be offset with the correct Timezone adjustments for the client (Im happy to assume that they are still in the same timezone as when they created the appointment).
The real problem comes with Daylight Savings adjustments, so for instance I might have appointments stored for Saturday 30th October 2010 at 1pm (BST[GMT+60]) and Monday 1st November 2010 at 1pm (GMT).
So as you can imagine, I cant just use the current timezone offset (BST) as that would mean that the appointment on Monday 1st November would be listed as 2pm rather than 1pm (GMT+60)
It occurs to me that the best way to deal with this is just to store the timezone offset with each appointment individually, but I feel it would be much better to be able to determine the original timezone correctly in the first place, then just let java do the correct adjustments.