How to compare two timestamps - differing only because one has a timezone? - date

I'm trying to test that the time.Time value I inserted into a postgres database is the same one I am querying out. Postgres drops the timezone though, so I'm wondering how can I get this testify/assert test to pass?
s.Equal(want.Date, got.Date)
Both are the dame datatype time.Time but the first has the timezone:
2020-10-31 00:00:00 +0000 UTC
I created this value like this - time.Date() must take a location, so I couldn't create it without one by passing nil:
want.Date := time.Date(2020, 10, 31, 00, 00, 00, 0000, time.UTC)
got.Date coming from the database looks like:
2020-10-31 00:00:00 +0000 +0000
I can't change the database dropping the timezone, so how can I change how I create the date or how can I drop the timezone? Or perhaps there is another way I can assert that the year, month, and day, are the same?

Use time.Time.Equal to test if two values of time.Time type are equal or not.
$ go doc time.Time.Equal
package time // import "time"
func (t Time) Equal(u Time) bool
Equal reports whether t and u represent the same time instant. Two times can
be equal even if they are in different locations. For example, 6:00 +0200
and 4:00 UTC are Equal. See the documentation on the Time type for the
pitfalls of using == with Time values; most code should use Equal instead.

Related

hive timezone conversion with short Timezone IDs

I am trying to convert UTC time to Local Timezone. I only require the date to be extracted. When I try the below it works and gives correct results.
select to_date(FROM_UTC_TIMESTAMP(current_timestamp(), 'Pacific/Fiji'));
But if I try, short ID of the respective timezone it is giving wrong results.
select to_date(FROM_UTC_TIMESTAMP(current_timestamp(), 'FJT'));
The issue was with the difference in GMT and UTC short IDs. In the above example 'Pacific/Fiji' is a UTC based short ID where are 'FJT' is GMT equivalent. Since we are using hive function FROM_UTC_TIMESTAMP we have to use UTC based short IDs. Here is a list of UTC based short IDs

MongoDb search on date field

I have a Mongo collection with 'DateAdded' in ISODate format
{
"_id" : 4098199,
"DateAdded" : ISODate("2018-08-31T05:06:13.150Z")
}
so it is 1hour off then local datetime
LocalDatetime is 2018-08-31 06:06:13 +01:00
UTC is 2018-08-31T05:06:13.150Z
Using following query when i try to get records added after 2018-08-31 06:00:00 i m not getting this records as it is in UTC
db.getCollection('User').find({"DateAdded":{$gte: new ISODate('2018-08-31T6:00:00Z')}})
How to convert UTC date while doing search on date field in MongoDB?
First of all ISODate('2018-08-31T6:00:00Z') has a typo - it should be 06:00:00Z. Without leading 0 ISODate helper returns '2018-08-31T00:00:00Z' 0am UTC and the query actually returns the document.
Secondly, there is nothing about local time. ISODate is in UTC, so
ISODate("2018-08-31T05:06:13.150Z") is 5am UTC and ISODate("2018-08-31T06:06:13.150Z") is 6am UTC. 5 < 6, so the $gte condition doesn't meet and the document is not returned.
Lastly, if you want to use local time - use Date instead:
db.getCollection('User').find({"DateAdded":{$gte: new Date('2018-08-31T6:00:00')}})
Will return all documents created after 5am UTC, 6am local time. Note, there is no Z at the end, which specifies UTC timezone.
As a recommendation - don't mess up with local time. Convert it to UTC as soon as possible and always work with UTC.

Understanding this date format - Redtail

What date format is this: -147114000000-0700. It is supposed to be 05/04/1965.
The first term looks like a unix timestamp. But then why would we need the second term?
I am using Redtail's api, but they provide negligible documentation on this. They are sending over a date looking like "/Date(-147114000000-0700)/". I have never seen this format before. Ignoring all the useless text, we get -147114000000-0700, still leaving me puzzled.
The -147114000000 value is a unix timestamp in milliseconds: it represents the number of milliseconds since unix epoch (which is 1970-01-01T00:00Z or January 1st 1970 at midnight in UTC).
As the number -147114000000 is negative, it represents a date before epoch. In this case, 1965-05-04T07:00:00Z (or May 4th 1965 at 7 AM in UTC).
-0700 is an UTC offset: it represents the difference from UTC. In this case, 7 hours behind UTC, which results in 1965-05-04T00:00-07:00 (or May 4th 1965 at midnight in -07:00 offset). Note that an offset can be written as -07:00, -0700 or -07.
But keep in mind that this same value can represent a different date and time in each timezone. For example, in Pacific/Honolulu timezone (that uses the -10:00 offset since 1947), the same timestamp corresponds to 1965-05-03T21:00-10:00 (May 3rd 1965 at 9 PM, in offset -10:00). So the corresponding date and time will depend on what timezone you convert this to.
That being said, probably the purpose of having the offset is just to tell you what's the offset that the date/time refers to, so it prevents you from converting to a different offset (where you can get different values for local date and time).
Just reminding that -0700 is not a timezone, it's just an offset. Actually, a timezone is the set of all offsets that a region had, has and will have during its history, while the offset is just the difference from UTC (check the section TimeZone != Offset in the timezone tag description). There can be more than one timezone that uses the same offset, so you can't really say in what timezone this is in.

PostgreSQL date() with timezone

I'm having an issue selecting dates properly from Postgres - they are being stored in UTC, but
not converting with the Date() function properly.
Converting the timestamp to a date gives me the wrong date if it's past 4pm PST.
2012-06-21 should be 2012-06-20 in this case.
The starts_at column datatype is timestamp without time zone. Here are my queries:
Without converting to PST timezone:
Select starts_at from schedules where id = 40;
starts_at
---------------------
2012-06-21 01:00:00
Converting gives this:
Select (starts_at at time zone 'pst') from schedules where id = 40;
timezone
------------------------
2012-06-21 02:00:00-07
But neither convert to the correct date in the timezone.
Basically what you want is:
$ select starts_at AT TIME ZONE 'UTC' AT TIME ZONE 'US/Pacific' from schedules where id = 40
I got the solution from this article is below, which is straight GOLD!!! It explains this non-trivial issue very clearly, give it a read if you wish to understand pstgrsql TZ management better.
Expressing PostgreSQL timestamps without zones in local time
Here is what is going on. First you should know that 'PST timezone is 8 hours behind UTC timezone so for instance Jan 1st 2014, 4:30 PM PST (Wed, 01 Jan 2014 16:00:30 -0800) is equivalent to Jan 2nd 2014, 00:30 AM UTC (Thu, 02 Jan 2014 00:00:30 +0000). Any time after 4:00pm in PST slips over to the next day, interpreted as UTC.
Also, as Erwin Brandstetter mentioned above, postresql has two type of timestamps data type, one with a timezone and one without.
If your timestamps include a timezone, then a simple:
$ select starts_at AT TIME ZONE 'US/Pacific' from schedules where id = 40
will work. However if your timestamp is timezoneless, executing the above command will not work, and you must FIRST convert your timezoneless timestamp to a timestamp with a timezone, namely a UTC timezone, and ONLY THEN convert it to your desired 'PST' or 'US/Pacific' (which are the same up to some daylight saving time issues. I think you should be fine with either).
Let me demonstrate with an example where I create a timezoneless timestamp. Let's assume for convenience that our local timezone is indeed 'PST' (if it weren't then it gets a tiny bit more complicated which is unnecessary for the purpose of this explanation).
Say I have:
$ select timestamp '2014-01-2 00:30:00' AS a, timestamp '2014-01-2 00:30:00' AT TIME ZONE 'UTC' AS b, timestamp '2014-01-2 00:30:00' AT TIME ZONE 'UTC' AT TIME ZONE 'PST' AS c, timestamp '2014-01-2 00:30:00' AT TIME ZONE 'PST' AS d
This will yield:
"a"=>"2014-01-02 00:30:00" (This is the timezoneless timestamp)
"b"=>"2014-01-02 00:30:00+00" (This is the UTC TZ timestamp, note that up to a timezone, it is equivalent to the timezoneless one)
"c"=>"2014-01-01 16:30:00" (This is the correct 'PST' TZ conversion of the UTC timezone, if you read the documentation postgresql will not print the actual TZ for this conversion)
"d"=>"2014-01-02 08:30:00+00"
The last timestamp is the reason for all the confusion regarding converting timezoneless timestamp from UTC to 'PST' in postgresql. When we write:
timestamp '2014-01-2 00:30:00' AT TIME ZONE 'PST' AS d
We are taking a timezoneless timestamp and try to convert it to 'PST TZ (we indirectly assume that postgresql will understand that we want it to convert the timestamp from a UTC TZ, but postresql has plans of its own!). In practice, what postgresql does is it takes the timezoneless timestamp ('2014-01-2 00:30:00) and treats it as if it WERE ALREADY a 'PST' TZ timestamp (i.e: 2014-01-2 00:30:00 -0800) and converts that to UTC timezone!!! So it actually pushes it 8 hours ahead instead of back! Thus we get (2014-01-02 08:30:00+00).
Anyway, this last (un-intuitive) behavior is the cause of all confusion. Read the article if you want a more thorough explanation, I actually got results which are a bit different then their on this last part, but the general idea is the same.
I don't see the exact type of starts_at in your question. You really should include this information, it is the key to the solution. I'll have to guess.
PostgreSQL always stores UTC time for the type timestamp with time zone internally. Input and output (display) are adjusted to the current timezone setting or to the given time zone. The effect of AT TIME ZONE also changes with the underlying data type. See:
Ignoring time zones altogether in Rails and PostgreSQL
If you extract a date from type timestamp [without time zone], you get the date for the current time zone. The day in the output will be the same as in the display of the timestamp value.
If you extract a date from type timestamp with time zone (timestamptz for short), the time zone offset is "applied" first. You still get the date for the current time zone, which agrees with the display of the timestamp. The same point in time translates to the next day in parts of Europe, when it is past 4 p.m. in California for instance. To get the date for a certain time zone, apply AT TIME ZONE first.
Therefore, what you describe at the top of the question contradicts your example.
Given that starts_at is a timestamp [without time zone] and the time on your server is set to the local time. Test with:
SELECT now();
Does it display the same time as a clock on your wall? If yes (and the db server is running with correct time), the timezone setting of your current session agrees with your local time zone. If no, you may want to visit the setting of timezone in your postgresql.conf or your client for the session. Details in the manual.
Be aware that the timezone offset used the opposite sign of what's displayed in timestamp literals. See:
Peculiar time zone handling in a Postgres database
To get your local date from starts_at just
SELECT starts_at::date
Tantamount to:
SELECT date(starts_at)
BTW, your local time is at UTC-7 right now, not UTC-8, because daylight savings time is in effect (not among the brighter ideas of the human race).
Pacific Standard TIME (PST) is normally 8 hours "earlier" (bigger timestamp value) than UTC (Universal Time Zone), but during daylight saving periods (like now) it can be 7 hours. That's why timestamptz is displayed as 2012-06-21 02:00:00-07 in your example. The construct AT TIME ZONE 'PST' takes daylight saving time into account. These two expressions yield different results (one in winter, one in summer) and may result in different dates when cast:
SELECT '2012-06-21 01:00:00'::timestamp AT TIME ZONE 'PST'
, '2012-12-21 01:00:00'::timestamp AT TIME ZONE 'PST'
I know this is an old one but You may want to consider using AT TIME ZONE "US/Pacific" when casting to avoid any PST/PDT issues. So
SELECT starts_at::TIMESTAMPTZ AT TIME ZONE "US/Pacific"
FROM schedules
WHERE ID = '40';

JPA Date and Timezone confusion

I'm having a problem reading dates from a database using JPA. I'm using EclipseLink and PostgreSQL
I've populated my database from a CSV file, witch had dates as strings (in this format: 6/30/2009-23:59:56). I used the following snipet to convert it to a Date object:
public static Date parseDate(String s){
DateFormat formatter = new SimpleDateFormat("d/M/yyyy-k:m:s");
try {
return new Date( ((java.util.Date)formatter.parse(s)).getTime() );
} catch (ParseException ex) {
Logger.getLogger(Type.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
The date is correctly converted and stored in the database as expected. Here is how i map the Date object to the database:
#Column(name="data_ts", nullable=false)
#Temporal(TemporalType.TIMESTAMP)
private Date dataTs;
The problem seems to happen when i try to read the Date from the database to use it in a chart(Highcharts). The record with that same timestamp above get read as:
Mon Jun 06 23:59:56 BRT 2011 and it's timestamp as 1307415596000
Note that it is in Brazilian Time(+3h), so the timestamp (that is calculated from GMT) is 3 hours shifted. Once ploted, the timestamp turns to point to 07/06/2011 02:59:56
Here's an example:
List<TimedataEnt> timeData = currentWellsite.getTimeData();
String debug = timeData.get(timeData.size()-1).getDataTs().toString() + ">>>" + timeData.get(timeData.size()-1).getDataTs().getTime();
where currentWellsite is and JPA Entity, and getDataTs() returns a java.util.Date object.
The string turns out to be "Tue Jun 30 23:59:56 BRT 2009>>>1246417196000"
How do I tell JPA not to convert the timestamp read from the database?
As said, Date and Timestamps have no timezone consideration. It seems that the issue is caused because Java considers that the time it reads from the database is the current default timezone.
So, if the database contais 2011-04-04 14:00:00 and my current timezone is +3, assigning that to java Date will generate 2011-04-04 14:00:00 BRT time(+3), with a timestamp shifted 3 hours (since timestamps are caclulated from UTC).
Solved the issue by getting an calculated timestamp:
long ts = myDate().getTime() + TimeZone.getDefault().getRawOffset();
It's important to say that getRawOffset() does not take Daylight Saving periods in consideration. For that, use getOffset()
Your date is 6/30/2009-23:59:56. I read that as 30 june 2009, 23:59:56. So the format to parse it should be M/d/yyyy-HH:mm:ss or M/d/yyyy-kk:mm:ss (depending on if your hours go from 1 to 24 or from 0 to 23). But definitely not d/M/yyyy-k:m:s: the month comes before the day.
Also, a Timestamp doesn't have any time zone. It's a universal instant in time. It's only when you display its value that the timezone is important, because then you have to choose which time zone to use to display the time. Use a DateFormat with the appropriate timezone set to display your timestamp.
Your issue seems to be that you are storing your Timestamp (which does not have a timezone) into a java.util.Date (which has a timezone offset).
If you want control over how the timezone is set, then store your Timestamp as a java.sql.Timestamp, or use your own #Converter.
In general Calendar should be used in Java instead of java.util.Date, which is for the most part deprecated. Calendar also has a Timezone, so you may have similar issues.