I can easily get the system Unix millisecond timestamp, but how can I convert it into something I can query with Diesel? The table in my schema has a Timestampz field (timestamp with time zone) that I need to compare to the Unix timestamp.
use diesel::sql_types::Timestamptz;
fn main() {
let unix_time: i64 = 123456;
let time: Timestamptz = ???
}
[dependencies]
diesel = { version = "1.4.7", features = ["postgres"] }
Timestamptz can be created from a PgTimestamp, chrono::NaiveDateTime or chrono::DateTime according to the docs.
I don't think there is a direct way to generate a timestamptz, and it's supposed to be opaque in most instances. Instead where a queries requires a Timetamptz you can pass a NaiveDateTime and load a NaiveDateTime back.
Now we use NaiveDateTime as it's the only one that can be created from a unix timestamp. DateTime requires an explicit timezone and can be generated from a NaiveDateTime.
use chrono::NaiveDateTime;
fn main() {
let conn = get_connection();
let ndt = NaiveDateTime::from_timestamp(0, 42_000_000);
let (id, date) = users
// assume a "created" column being a Timestamptz
// you can just pass a NaiveDateTime.
.filter(created.gt(ndt))
.select((user_id, created))
// We load back a NaiveDateTime and never deal with Timestamptz directly.
.first::<(u64, NaiveDateTime)>(&conn)
.expect("query failed");
}
Related
I'm learning golang atm, and currently I'm using gorm trying to select query getting date column, but it keep returning '2020-01-10T00:00:00Z', how do I get rid of the timezone?
I've tried changing date to time.Time or string, nothing works, here is the code
type Price struct {
DateStay time.Time `json:"date"`
Price int `json:"price"`
}
Update:
This is the code that I am using
var price []models.Price
err = models.DB.Raw(`
SELECT P.date_stay, P.price
FROM prices p
WHERE P.room_type_id = ?
`, roomTypeId).Scan(&price).Error
I tried to P.date_stay::date, date(P.date_stay) on the query but nothing works
I expect it to return '2020-01-10'
Using time.Time as a type for the date is probably best.
You can format the result of the date by setting the format to the desired date format you want.
(dd-mm-yyyy or whatever order you please).
Then you can format the value using time.Parse(format, date)
format := "2000-01-13"
formattedDate, err := time.Parse(format, price.DateStay)
assuming price is a result from your select query.
If you time is a time.Time you can try using price.DateStay.Format(format)
How to covert a PostgreSQL timestamp (with time zone) to Rust Chrono DateTime<Utc>?
Example: 2020-04-12 22:10:57.0+02
You have to use the custom parser from str:
let date_str = "2020-04-12 22:10:57.000+02";
// convert the string into DateTime<FixedOffset>
let datetime = DateTime::parse_from_str(&date_str, "%Y-%m-%d %H:%M:%S%.f%#z").unwrap();
// convert the string into DateTime<Utc> or other timezone
let datetime_utc = datetime.with_timezone(&Utc);
Extra info:
%.f => .026490: Similar to .%f but left-aligned. These all consume the leading dot.
%#z => +09: Parsing only: Same as %z but allows minutes to be missing or present.
For more info, see this awnser.
The Postgres type TIMESTAMP is only convertible to chrono's NaiveDateTime.
In order to convert to chrono's DateTime<Utc>, you must use the Postgres type TIMESTAMP WITH TIME ZONE for your column.
I'm currently parsing a time string and saving it to the db (Postgresql):
event.Time, _ := time.Parse("3:04 PM", "9:00 PM")
// value of event.Time now is: 0000-01-01 21:00:00 +0000 UTC
db.Create(&event)
It's giving me this error: pq: R:"DateTimeParseError" S:"ERROR" C:"22008" M:"date/time field value out of range: \"0000-01-01T21:00:00Z\"" F:"datetime.c" L:"3540"
event.Time's type is time.Time.
I also tried setting event.Time's type to string and using time data type in postgresql:
type Event struct {
Time string `gorm:"type:time
}
But now I'm getting an error when fetching records in the db:
sql: Scan error on column index 4: unsupported driver -> Scan pair: time.Time -> *string
Investigated this issue further. Currently, there's no support in GORM for any Date/Time types except timestamp with time zone
See this part of code from dialect_postgres.go:
case reflect.Struct:
if _, ok := dataValue.Interface().(time.Time); ok {
sqlType = "timestamp with time zone"
}
So basically I see two options for you:
Either use varchar(10) in DB, and string in Go, an simply save it as "9:00 PM" (where 10 is some number that suits you)
Or use timestamp with time zone in DB, time.Time in Go, and format your date part as a constant date, 01/01/1970, for example:
time.Parse("2006-01-02 3:04PM", "1970-01-01 9:00PM")
In that case you'll have to omit the date part in your presentation, but if you plan to select by date range, that could work better for you.
You can set an arbitrary database-specific type with Gorm using sql tag
type Event struct {
Time time.Time `sql:"type:timestamp without time zone"`
}
When updating the DATETIME field in SQL, the Go string must be in this format: time.Now().Format(time.RFC3339).
From Postgres perspective the error stems from there being no year 0000. If you don't the date you may just be able to add 1 year to the converted timestamp giving '0001-01-01T21:00:00+00' which is a valid Postgres timestamp.
select '0000-01-01T21:00:00+00'::timestamptz at time zone 'UTC'
ERROR: date/time field value out of range: "0000-01-01T21:00:00+00"
Gives he same error. And just as a demonstration 1 day before 0001-01-01 gives:
select '0001-01-01T21:00:00+00'::timestamptz at time zone 'UTC' - interval '1 day' "day_before_1/1/1";
--day_before_1/1/1
--0001-12-31 21:00:00 BC
Since I am already getting down voted I decided to give some more details to my problem.
My problem is that I want to store times. Times only for easy comparison. To me it makes sense to define it as following:
00:00:00 = (long) 0L
24:00:00 = (long) 24*60*60*1000L
The PostgreSQL documentation says about TIME WITHOUT TIME ZONE this:
time [ (p) ] [ without time zone ]
8 bytes | time of day (no date) | 00:00:00 - 24:00:00 | 1 microsecond / 14 digits
But for some reason, somewhere along the way from my database to my web application the timestamps are getting messed up.
In the following I want to show you that I am storing TIME WITHOUT TIME ZONE, mapped from LocalTime (jodatime), into my database and afterwards fetch it back.
Fetching it back from the database and mapping it back into a LocalTime object will give me something like 23 Feb 2016 08:00:00 GMT which is
1456214400000 and that is > 24*60*60*1000.
There are 3 to 4 options:
PostgresSQL stores actually the whole TIMESTAMP and shows HH:mm:ss just for presentation
jodatime is inventing things here that are not there.
(very unlikely) The mapper I am using does more than I tell him. But that is unlikely since the mapper does not touch anything.
(probably true) I myself mess things up somehow.
More details:
I decided to add some more details. I am creating a record for my table shop_times
private Long createShopTimes(Long shopId, DateTime dayFrom, DateTime dayTo, LocalTime timeFrom, LocalTime timeTo, DayOfWeek dayOfWeek, ShopTimesType shopTimesType) {
Long timePeriodId = this.ctx.insertInto(SHOP_TIMES)
.set(SHOP_TIMES.SHOP_ID, shopId)
.set(SHOP_TIMES.DAY_OF_WEEK_ID, dayOfWeek)
.set(SHOP_TIMES.SHOP_TIMES_TYPE_ID, shopTimesType)
.set(SHOP_TIMES.DAY_FROM, dayFrom)
.set(SHOP_TIMES.DAY_TO, dayTo)
.set(SHOP_TIMES.TIME_FROM, timeFrom)
.set(SHOP_TIMES.TIME_TO, timeTo)
.returning(SHOP_TIMES.ID)
.fetchOne().getValue(SHOP_TIMES.ID);
List<ShopTimesRecord> fetchInto = this.ctx.select(
SHOP_TIMES.TIME_FROM,
SHOP_TIMES.TIME_TO
)
.from(SHOP_TIMES)
.fetchInto(ShopTimesRecord.class);
for (ShopTimesRecord shopTimesRecord : fetchInto) {
if(shopTimesRecord.getTimeFrom().toDateTimeToday().getMillis() > 24*60*60*1000L) {
System.err.println("This should not happen..");
}
Date from = new Date(shopTimesRecord.getTimeFrom().toDateTimeToday().getMillis());
Date to = new Date(shopTimesRecord.getTimeTo().toDateTimeToday().getMillis());
System.out.println(from.toGMTString());
System.out.println(shopTimesRecord.getTimeFrom().toDateTimeToday().getMillis());
System.out.println(to.toGMTString());
System.out.println(shopTimesRecord.getTimeTo().toDateTimeToday().getMillis());
}
return timePeriodId;
}
As you can see, I am getting something that I would not expect at this point:
This should not happen..
23 Feb 2016 08:00:00 GMT
1456214400000
23 Feb 2016 20:00:00 GMT
1456257600000
This is the table shop_times that I am using to store timing information:
CREATE TABLE shop_times (
-- PRIMARY KEY
id BIGSERIAL PRIMARY KEY,
-- FOREIGN KEYS
shop_id BIGINT NOT NULL,
CONSTRAINT fk__shop_times__shop
FOREIGN KEY (shop_id)
REFERENCES shop(id),
shop_times_type_id BIGINT NOT NULL,
CONSTRAINT fk_shop_times__shop_times_type
FOREIGN KEY (shop_times_type_id)
REFERENCES shop_times_type(id),
day_of_week_id BIGINT NOT NULL,
CONSTRAINT fk__shop_times__day_of_week
FOREIGN KEY (day_of_week_id)
REFERENCES day_of_week(id),
-- ATTRIBUTES
day_from TIMESTAMP WITH TIME ZONE NOT NULL,
day_to TIMESTAMP WITH TIME ZONE NOT NULL,
time_from TIME WITHOUT TIME ZONE NOT NULL,
time_to TIME WITHOUT TIME ZONE NOT NULL,
-- CONSTRAINTS
CHECK(day_from < day_to),
CHECK(time_from < time_to)
);
The mapper I am using. But as you can see it is just taking the time it gets and passes it further;
public class TimeWithoutTzToJodaLocalTimeConverter implements Converter<Time, LocalTime> {
private static final long serialVersionUID = -2736422625956918206L;
#Override
public LocalTime from(Time timestamp) {
LocalTime dateTime = new LocalTime(timestamp.getTime());
return dateTime;
}
#Override
public Time to(LocalTime localTime) {
Time time = new Time(localTime.toDateTimeToday().getMillis());
return time;
}
#Override
public Class<Time> fromType() {
return Time.class;
}
#Override
public Class<LocalTime> toType() {
return LocalTime.class;
}
}
Sorry - don't believe you.
=> SELECT '24:00:00'::time without time zone;
time
----------
24:00:00
(1 row)
=> SELECT '24:00:01'::time without time zone;
ERROR: date/time field value out of range: "24:00:01"
LINE 1: SELECT '24:00:01'::time without time zone;
You're creating a full DateTime:
.toDateTimeToday()
http://joda-time.sourceforge.net/api-release/org/joda/time/TimeOfDay.html#toDateTimeToday%28%29
I am using the following code in my controller:
#monday = (Time.now).at_beginning_of_week
#friday = 5.days.since(#monday)-1.second
#sent_emails = ContactEmail.all(:conditions => ['date_sent >= ? and date_sent <= ?', #monday, #friday])
Although it works fine on my local sqlite, I have an "operator does not exist timestamp without timezone = integer" error.
I'm not exactly clear what to change.
Ideas?
Thanks.
Your parameters #monday and #friday are wrong, these have to be of type "timestamp without time zone" but are created as integers, see the errormessage. SQLite doesn't have any datetime-datatypes, so dates are stored as text or integers (unix-timestamps). This is why you don't get an errormessage in SQLite.
Make sure you create timestamps like '2004-10-19 10:23:54' and you will be fine. Another option could be the PostgreSQL-function to_timestamp() to convert your unix-timestamp to a timestamp:
#sent_emails = ContactEmail.all(:conditions => ['date_sent >= to_timestamp(?) and date_sent <= to_timestamp(?)', #monday, #friday])