DateTime + 2x Time vs. DateTime + Duration for storing time - datetime

I'm trying to implement a ReservationController which is responsible for taking reservations of something for a specific time range. So far I guessed using one column for the Date (DateTime) and two columns for the time span (2x Time) in the database would be a good idea. Especially when it comes to queries on date, this approach is easier because I know, that the DateTime column is always set to 12am. So I just query DateTime.Today for instance. But now I'm getting into trouble with reservations which are passing the day border (eg. Today 22pm - Tomorrow 1am). Could you please give me some advice what is a common solution for this problem (what database schema I should use)?
regards

I would have thought just two DateTimes would be enough? You can still query whether start datetime or end datetime is today (i.e >= today midnight and < tomorrow midnight).
Perhaps I am missing something - were there other queries you need to do, or were you worried about optimisation of this query? It should be fine, if you add one or more indexes for the DateTime columns.

Related

MSSQL and EntityFramework - Storing and reading utc datetime

I have a request to alter current columns which are type of 'time' and instead of capturing just time I need to capture so called "utc time".
My idea is to create a fixed codelist with all timezones, and then to reference it to a appropriate table as FK.
My questions are:
Can column of a type 'time' hold also an information regarding time zones (utc, for example 15:00:00 +2 (gmt + 2)) and if not, could you suggest me another type for that column?
Should I maybe need to separate it into two columns? For example: [15:00:00] - StartTime, [+2:00] - UtcOffset
EF Insert: When I do inserting to the db, for that particular column, should I convert my DateTime object to for example DateTimeOffset?
Thanks in advance.
From the comments in your question, it sounds like you are building an appointment scheduling system. I'll base my answer on that, because your specific questions aren't quite aligned to the scenario you described.
First, it's important to understand that the relationship between a time zone and an offset is a one-to-many relationship. One time zone can have multiple offsets. In other words, a time zone is not an offset, but rather a time zone has an offset.
A time zone represents a geographic region where the local time is the same throughout. It is identified by a string ID, such as "America/Los_Angeles" (an IANA time zone ID) or "Pacific Standard Time" (a Windows time zone ID). In .NET, you will use them on the TimeZoneInfo object with the Id instance property or methods like FindSystemTimeZonesById.
An offset is like -07:00 or +05:30 or even +13:45. Any given offset applies only at a particular date and time. For example, in America/Los_Angeles, either -08:00 or -07:00 apply depending on whether daylight saving time is in effect at a given point in time. Keep in mind that DST is not the only reason for offsets to be different - many time zones have changed their standard time at some point in their history.
Also, it's called an offset because it is deviated from UTC by a certain amount. UTC itself always has a zero offset, delineated either by +00:00 or sometimes by Z. It's similar to GMT, except in how it is defined. UTC applies universally, everywhere. GMT technically applies only on the prime meridian. They both refer to the zero offset. You should prefer to say "UTC" in most cases.
Next, you should separate your application logic between future scheduling and present/past record keeping.
Present/past is the easier of the two. Since the moment in time has actually occurred, the local time and its offset from UTC is fixed forever. You can either store the local time and its offset in a single .NET DateTimeOffset structure (mapped to a datetimeoffset field in SQL Server). In other words, you can simply store 2021-07-27T12:00:00-08:00.
Note that you could instead store the equivalent UTC date and time, which would be 2021-07-27T20:00:00+00:00. However you've then lost the local time, and thus would need to convert back using the original time zone if you wanted to see that time. Some people prefer that, but I think it's more useful to store the original value.
For future scheduling, the situation is a bit different. Consider that the offset might not be the same for one appointment as it will be for the next appointment in the same time zone. Also consider that the definitions for which offset apply might change in between the time you schedule the appointment and when it comes around. (The likelihood of that increases the further out you schedule.)
Thus, for each location you should not store an offset, but rather a time zone identifier. Add a TimeZoneId to your object that stores each location (or each appointment depending on your model schema). Use TimeZoneInfo.GetSystemTimeZones to list the available time zones. The DisplayName property can be shown to your user, and the selected Id property gets assigned to the TimeZoneId.
Next you have to consider if you are scheduling a single appointment or creating a recurring appointment pattern.
For a single appointment you simply need the local date and time for that appointment. You can use a .NET DateTime struct (use datetime2 in SQL). Don't apply an offset, and don't convert to UTC. Just store the information provided.
For recurring appointments, you need to think through the information provided and store exactly what is given. For example, if the appointment is at 10:00 every other Tuesday, you'll need to store "10:00", "Tuesdays" and "2 week intervals". The data types for each will vary depending on how you choose to store and apply them. For example, you might use a time type for 10:00, but you could store the other values using integers. Appointments of different patterns could get stored in different ways.
Alternatively, some like to store patterns using a string containing a CRON expression. You can google that for more details.
Now you have everything you need to both schedule an appointment and record that appointment after it happens. But there's one part missing - you'll likely want some table of upcoming appointments that are easily queryable. For that, you've got a few options:
You can create a separate table via a background job of some kind. Periodically it would query all the appointments, use their information to compute the next upcoming appointment time, and insert it. You can store that in a DateTimeOffset, either as local time or as UTC. (SQL Server will always compute indexes on the equivalent UTC time either way.)
You could just add another field to your appointments that shows the next actual appointment time. You can then compute the next upcoming appointment whenever the appointment is created or updated, or when that appointment occurs, and update the table accordingly.
With either approach keep in mind that you will want to periodically check for time zone data updates (either via Windows Update or keeping the tzdata package current on Linux). You will also want to periodically re-compute future appointment times, in case that time zone data has been modified in a way that affects the appointments.
If all of this sounds super complicated - sorry, but it is. Doing scheduling worldwide across time zones right is challenging. If you want it simpler, you might want to look into a pre-made solution such as Quartz.NET, which you can integrate into your application.

What is the best way to store datetime value in documentdb?

Is there a best way to store datetime value in documentdb?
Obviously I will be storing this information in UTC and ISO 8601 formats. Are there any gotchas with this?
I should be able to query based on this datetime value such startDateTime < currentValue and currentValue <= endDateTime etc. What should I do to get maximum performance on these types of queries etc.
In your case, the only real key that you didn't mention is that you have a range index with full precision (-1) on the ISO-8601 strings.
Some other general guidelines:
Store all events in canonical form: 2016-07-18T01:23:45.678Z
Store everything in zulu/GMT time. End every string with a Z. Never store it with +03:00. Make sure you shift local time input from the user to zulu time before running queries with that input.
I also recommend that you use the most coarse granularity for your situation. So, if you are referring to the entire month of march, 2016, simply store 2016-03 leaving off the -01T00:00:00.000Z. This mostly applies to the literals you use when running queries. Assuming the events are stored in canonical form than 2016-07 < 2016-07-18T01:23:45.678Z is true. This recommendation is mostly for the benefit of the user, but it won't cause any performance degradation and it's possible that it could be a very slight improvement in some circumstances.

SQLITE datetime for different timzone required, not only localtime

I want to fetch date and time, in different timezone using SQLITE. Say, I get the value as, 20160118T010856 in input, but I require it to change to Australian, England and other timezone.
What I am currently able to do is :
select datetime('2016-01-18T04:13:39','localtime');
Which only provides me for my current local time. Kindly help.
As far as I know this is not possible in sqlite. Your best bet is to store the datetime as UTC and do the conversion outside the database.
From the documentation you could apply an offset(modifier) to a date and time, but it doesn't take Daylight Savings Time into account.

Issue regarding epoch in SQLite

I've done a web application using PHP and postgres. Now, that same application I'm translating to JavaScript and SQLite. I must say, it's not been too tough and SQLite has successfully been able to interpret the same queries as I use in postgres.
Except for this one.
SELECT SUM(t.subtotal)/MAX(EXTRACT(epoch FROM (r.fecha_out - r.fecha_in))/86400) AS subtotal,
COUNT(t.id) AS habitaciones FROM reserva_habitacion t
LEFT JOIN reserva r ON t.id_reserva=r.id
WHERE (r.fecha_in <= "2015-03-27" AND r.fecha_out > "2015-03-27") AND r.estado <> 5
Using the FireFox plugin "SQLiteManager" it hints me that the error is this part epoch FROM, but I cannot get my head around it. What am I doing wrong and how could I fix it?
Any suggestions are welcome!
SQLite, unusually for a relational database, is completely dynamically typed, as discussed in this manual page.
Postgres, in contrast, is strictly typed, and uses operator overloading so that timestamp - timestamp gives you an interval. An interval can then be passed to the SQL-standard extract() function, in this case to give a total number of seconds between two timestamps. (See the manual page on Date/Time functions and operators.)
In SQLite, you have no such column type, so you have two choices:
Store your DateTimes as Unix timestamps directly; at this point, the extract epoch from is redundant, because r.fecha_out - r.fecha_in will give you the difference in seconds.
Store your DateTimes as strings in a standard format, and use the SQLite Date and Time functions to work with them. In this case, you could use strftime('%s', foo) to convert each value to a Unix timestamp, e.g. strftime('%s', r.fecha_out) - strftime('%s', r.fecha_in)

Calculate the length of a Date/Time interval in days, hours, and minutes

I have created a table with a Start Date/time and an end Date/Time. Now I am trying to create a query that will calculate the difference between the Start date and the End date in Days, Hours, and Minutes. I am using Access 2013. I would like to do this in the table because in the end, I need to store the Days, Hours, and Minutes in a permanent record. However, I understand it's not good programming to do the calculation in the table. Any help would be appreciated.
To do the calculations "in the table" you could use a Before Change data macro. For a table with
Date/Time fields named [Started] and [Ended] to hold the start/end values, and
Long Integer fields named [DurationDays], [DurationHours], and [DurationMinutes] to hold the calculated values,
the following macro might do the trick:
For more information on Data Macros see
Create a data macro

Resources