As I spend most of my time with php and mysql or pgsql, I will use DateTime as a generic word for the date API. In php there is no "Date", "Time", "DateTime" and "DateTimeOffset"
As I develop web application more and more elaborate, I use DateTime most of time, but sometimes I wonder if it is really what I want.
for example it happens that I just want to display the today's date (for example when I want to store a forum or blog post), there is no calculation, no filter to provide, no iteration to happen... So why do I use \DateTime over the date() function?
I saw this topic that provides some simple description of the pros of each technologies.
But it does not really answer to the question. Is it really a loss to throw up 2 more bytes in a DateTime object in PHP and other 2 bytes in my database as it allows me to use the DATE_INTERVAL API (in php it is DateInterval) and the IntlDateFormatter.
Moreover, this post says that unix_timestamp is reserved from 1970. But it is not logical and some tests prove it :
echo date('d/m/Y',time(-1));
echoes '31/12/1969' ! And it is logical. A 32 bits unsigned int goes from 0 to 4 294 967 295 and there are only almost 2 billions of seconds in 68 years, so the int is signed and "negative timestamp" must exist !
Another think that is really important to me, and that makes me chose DateTime every time is that I want to deal with dates, not with integers. DateTime is a date, timestamp is not ! The only sense that I found to timestamp was the time I wanted to time-mark a filename because in that cas timestamp is timestamp...
However, ther is still a problem : timezone handling.
As MySQL and others does not handle timezone when storing dates as DateTime, for now, I use TimeZone integration as the escape part of "filter in escape out"
$toStoreDate = new \DateTime($_POST['date'],new DateTimeZone('UTC'));
$dao->exec('INSERT INTO mytable(mydate) VALUES (\''.$toStoreDate->format('Y-m-d h:i:s').'\')');
$toDisplayDate =new \DateTime( $dao->query('SELECT mydate FROM mytable')
->fetch(DAO::FETCH_ASSOC)['mydate']);
$toDisplayDate->setTimeZone(new DateTimeZone('myLocal'));
Is it the right way? Wouldn't it be better to store a simple timestamp and then get the good local time?
So, here is a summarise of the question :
Is the 2 more bytes of DateTime a loss in really simple use of the API (only displaying)
Is it the time to give up unix_timestamp?
Wouldn't it be better to store a simple timestamp and then get the good local time?
As said in a comment I believe this is mostly down to personal preference. In my eyes, the use of a Unix timestamp and "legacy" non-OOP interfaces is not the way to do it going forward in today's world, for instance, we don't (read: shouldn't be) using an INT datatype in our database to store dates in Unix Timestamp format, we should instead be using the database's native type which is usually a DATE or DATETIME type which cooperates with PHP's DateTime object (and other languages') almost natively when it comes to standard conversions.
To elaborate a bit on what I mean by standard conversions: When you use MySQL and pull back a value to PHP you get a ISO-formatted date string, of which the DateTime class parses in it's constructor giving you an immediately usable object. In contrast, to go the Unix timestamp route you would have to use strtotime, then date to get it into whatever format you want natively.
I mentioned before about interop between our PHP systems and .NET systems. Whilst there are no specific issues caused by using a timestamp it's simply not the practical solution, as again, we use a database that returns a DateTime value which can be sent straight down the pipe. If we were to convert this to a unix timestamp for use internally in PHP we'd also have to then convert it back out if we were to send a response, or send a response to the .NET Application (or should I just say API in this case) that is a timestamp, and convert it at the end. By using DateTime across the board, it alleviates the need for any conversions to happen whatsoever and the whole development process is easier.
Finally to add to all of this, as you also mentioned in your post, you get to use shiny items such as DateInterval, easier timezoning, easier manipulation and easier formatting etc when you use DateTime and it's related object-oriented partners in crime. It's just an easier development process in my eyes.
I don't believe as I initially said that there is a "correct" answer to this, just more of a personal preference based on your own coding style, and the comments above reflect mine.
Is the 2 more bytes of DateTime a loss in really simple use of the API (only displaying)
I do not believe so in any way. Especially with PHP scripts generally being such short running processes anyway.
Is it the time to give up unix_timestamp?
Yes :)
Wouldn't it be better to store a simple timestamp and then get the good local time?
See comments above on database, it's not "native" to use a Unix Timestamp for this purpose IMO. You can just call ->getTimezone and store this in the database, then use ->setTimezone when you pull it back out again.
Not an exact answer to your question, but I would choose Timestamp over DateTime, because I BELIEVE working on an Integer value is much more cost effective (measuring CPU's processing time), rather processing DateTime values.
I feel much comfortable when I have Numbers on a Binary Machine, rather having Strings or Objects.
Human vs. Machine
In terms of Understandability, I'd say when I'm writing a program for a computer, I would consider that I'm making that for a Machine to work on that, however if an abstraction over that layer could help the humans to understand that better, why not we don't use that when Performance is not an issue?
I can't remember who said or where I heard that, but someone said something like People hate Computers, but they should hate Programmers, and I'm totally agree with that. So, as a human I still keep respect of that machine and will try to make programs which are more understandable for computers. :)
Update:
To picture it better, imagine we have a program to deal with 'Dates', processing 10,000 times per minute, right?
// it LOOKS Better
$date = new DateTime();
$date->setDate(1986, 3, 24); // March 24, 1986
echo $date->format('Y-m-d');
// it WORKS Better
echo date("Y-m-d", mktime(0, 0, 0, 3, 24, 1986)); // March 24, 1986
Let say I've to look at this code for an hour per week, and let say there are 10,000 people that they should deal with that 24/7/365 and of course I'm not gonna handle that, it's a task for a machine.
By the way, I would say again that if Performance is not an issue, then why we don't make it more understandable for programmers? If we need to get the most out of that, then let programmers look at the code that Works better, not Looks! :)
Related
Disclaimer: I'm fully aware that the best way to represent date/times is either Unix timestamps or PHP's DateTime class and Oracle's DATE data type.
With that out of the way, I'm wondering what the most appropriate data types are (in PHP, as well as Oracle) for storing just time data. I'm not interested in storing a date component; only the time.
For example, say I had an employee entity, for which I wanted to store his/her typical work schedule. This employee might work 8:00am - 5:00pm. There are no date components to these times, so what should be used to store them and represent them?
Options I have considered:
As strings, with a standard format (likely 24-hour HH:MM:SS+Z).
As numbers in the range 0 <= n < 24, with fractional parts representing minutes/seconds (not able to store timezone info?).
As PHP DateTime and Oracle DATE with normalized/unused date component, such as 0001-01-01.
Same as above, only using Unix timestamps instead (PHP integer and Oracle TIMESTAMP).
Currently I'm using #3 above, but it sort of irks me that it seems like I'm misusing these data types. However, it provides the best usability as far as I can tell. Comparisons and sorts all work as expected in both PHP and Unix, timezone data can be maintained, and there's not really any special manipulation needed for displaying the data.
Am I overlooking anything, or is there a more appropriate way?
If you don't need the date at all, then what you need is the interval day data type. I haven't had the need to actually use that, but the following should work:
interval day(0) to second(6)
The option you use (3) is the best one.
Oracle has the following types for storing times and dates:
date
timestamp (with (local) time zone)
interval year to month
interval day to second
Interval data types are not an option for you, because you care when to start and when you finish. You could possibly use one date and one interval but this just seems inconsistent to me, as you still have one "incorrect" date.
All the other options you mentioned need more work on your side and probably also lead to decreased performance compared to the native date type.
More information on oracle date types: http://docs.oracle.com/cd/B19306_01/server.102/b14225/ch4datetime.htm#i1005946
I think that the most correct answer to this question is totally dependant on what you are planning to do with the data. If you are planning to do all your work in PHP and nothing in the database, the best way to store the data will be whatever is easiest for you to get the data in a format that assists you with what you are doing in PHP. That might indeed be storing them as strings. That may sound ghastly to a DBA, but you have to remember that the database is there to serve your application. On the other hand, if you are doing a lot of comparisons in the database with some fancy queries, be sure to store everything in the database in a format that makes your queries the most efficient.
If you are doing tasks like heavy loads calculating hours worked, converting into a decimal format may make things easier for calculations before a final conversion back to hours:minutes. A simple function can be written to convert a decimal to and fro when you are getting data from the database, convert it to decimal, do all your calculations, then run it back through to convert back into a time format.
Using unix timestamps is handy when you are calculating dates, probably not so much when you are calculating times though. While there seem to be some positives using this, such as very easily adding a timestamp to a timestamp, I have found that having to convert everything into timestamps to calculations is pesky and annoying, so I would steer clear of this scenario.
So, to sum up:
If you want to easily store, but not manipulate data, strings can be
an effective method. They are easy to read and verify. For anything
else, choose something else.
Calculating as numbers makes for super easy calculations. Convert
the time/date to a decimal, do all your heavy hiting, then revert to
a real time format and store.
Both PHP's Datetime and Oracle's Date are handy, and there are some
fantastic functions built into oracle and PHP to manipulate the
data, but even the best functions can be more difficult then adding
some decimals together. I think that storing the data in the
database in a date format is probably a safe idea - especially if
you want to do calculations based on the columns within a query.
What you plan to do with them inside PHP will determine how you use
them.
I would rule option four out right off the bat.
Edit: I just had an interesting chat with a friend about time types. Another thing you should be aware of is that sometimes time based objects can cause more problems than they solve. He was looking into an application where we track delivery dates and times. The data was in fact stored in datetime objects, but here is the catch: truck delivery times are set for a particular day and a delivery window. An acceptable delivery is either on time, or up to an hour after the time. This caused some havoc when a truck was to arrive at 11:30pm and turned up 45 minutes later. While still within the acceptable window, it was showing up as being the next day. Another issue was at a distribution center which actually works on a 4:00AM starting 24 hour day. Setting up times worked for the staff - and consolidating it to payments revolving around a normal date proved quite a headache.
I plan to capture the start and end of user initiated activities on my website using time() in php. I'm not sure if this is the best way to capture start/end times. Anyway, the data will be stored in MySQL, but again I'm not sure what datatype I should use.
Based on the answers I've read on stackoverflow, the datatype used depends on the purpose of the application.
Purpose of the application
At it's simplest, I want to record start, stop (and duration) of an
activity. Probably using time().
At it's most complicated I'd like to plot statistics based on when
the user did a certain activity, how much time they spent doing the
activity (in total), and when they were the most successful/least
successful etc, etc. (all based on the start/end times) Something to
keep in mind. The users will be from all over the world.
MORE INFO
If an activity is repeated a new record will be made for it. Records will not be updated.
At first, I had planned on storing unix timestamps in MySQL (as an integer datatype?), but from what I understand this is a bad idea, because I will lose a lot of MySQLs ability to process the information. If I store the information as DATETIME, but then move the server, all the times will change based on the local time of the server. Something I found confusing was that TIMESTAMP in MySQL is not the same as a unix timestamp- which is what I would be getting if I used time().
I'm aware that the unix timestamp can only hold dates up to 2038 for some systems, but that isn't a concern (at the moment).
Question: Should I use time() to capture start and end times for user initiated activities? Based on the purpose of the application, what datatype should I use to store the start and stop of user initiated activities?
THANKS
Thanks for the answers everyone. TBH I'm not convinced either way yet, so I'm still doing some research. I chose the TIMESTAMPS option because I really would like to store my information using UTC (GMT). It's a pity though that I will lose out on some of MySQLs inbuilt time functions. Anyway thanks again for your answers.
If you're going worldwide, MySQL's TIMESTAMP is almost universally a good choice over DATETIME, since it stores the time as UTC instead of local time so DST changes won't cause you problems if analyzing in multiple time zones.
Having a non DST changing time zone as a base can be a life saver, converting between multiple time zones with different DST changeover dates can really cause problems, consider for example having a timestamp during the hour that happens twice in a change from summer- to winter time.
Use DATETIME to store the time and use date('Y-m-d H:i:s') to get the current time to store it. When you fetch this value, you will get the time in this format.
To convert it to a timestamp, use $timestamp=strtotime($fetchedValue) To display this in another format use date('H:i',$timestamp). Read about formats from date manual of php
TIMESTAMP can only store values after Jan 1 1970, since it stores timezone data.
So if you are trying to store a date before Jan 1 1970, its better to use DATETIME.
Frankly, TIMESTAMP is useful only if you are actively syncing raw data between two machines with different timezone
When building PHP applications I always end up having trouble trying to get everything to play right with server times and timezones.
I generally have a simple timestamp-like field on most of my records that isn't updated - just static for reference purposes. I use it to track when events happened, when users registered, when comments were created etc.
I have been trying to follow the best practices of using a Datetime field to store this value. The problem is that when using different servers they often have different timezones so the datetime's don't match up even close unless I add more code to offset the differences. This can also be a problem when using MySQL replication and NOW() queries since their is often a lag.
I'm wondering if I should go back to using ints since they don't seem to care anything about timezones and only require the server clock is set. The downfall is that all those MySQL date/time functions (I never use) can't be used which might be a problem in the future. The upside is that I can cut the storage space in half by moving back to 4byte ints instead of datetimes.
People also mention that ints will only work until 2037 - why is that a problem? Who expects to be using PHP + MySQL in 2037?
Is there anything I am missing? Is it better to store reference times in an agnostic way like Unix timestamps?
I use date/time fields in all my database work but store everything in GMT. Pretty much the first opportunity my code gets it converts something into GMT, and does all its internal math in gmt, etc. The only time I convert it back out of GMT into local time is when displaying to the user. PHP has unixtime() which is GMT, plus gmstrftime and gmdate, pretty much anything you'll ever need.
As the title states, I want to get the difference (in seconds) between 2 (specifically between now and a date in the past) dates without using: strtotime, the Zend Framework or a PEAR package.
I don't want to get into the details of my reason but the gist of it is that I'm working with very old dates (and I do mean old, I'm talking before 0 A.D.).
It is preferred that the returned result be highly accurate down to the second of the textual timestamp given. The format to call the function should be similar to:
$bar = foo("YYYY-MM-DD HH:MM:SS", "AD"); // Where AD is Anno Domini
$baz = foo("YYYY-MM-DD HH:MM:SS", "BC"); // Where BC is Before Christ
The first person who offers a working that features:
High readability
No magic (ternary operators, etc.)
Will have their answer up-voted and accepted. Their name will be credited in the header of the source file which uses their code.
EDIT (Re: Fame):
Someone said having a name credited in the header looks bad and can be edited out. I'm talking about the header of the source file that utilizes the function I want. This isn't about "fame". Credit should be given where credit is due and I have no need to lie about who authored a work.
EDIT (Re: Accurateness):
No reason other than I want to keep with the "letter of the message" as best as I am able.
EDIT (Re: Magic):
Magic is different things to different people. In regards to the ternary operator, please respect my opinion as I respect yours. Thank you.
EDIT (Re: Old Dates and One Second Accuracy):
As a student of history, it makes sense to me. The desire for "one second accuracy" is not an absolute. Perfection, while attainable, is not required.
I'd suggest splitting each datetime into parts (year, month, date, hours, minutes, seconds). Then, with each part, do a basic sum of most more minus less recent (remembering that a BC date is effectively a negative number).
You'll never get it absolutely correct. You're going to have to consider leap years, and whether a century year is a leap year, the switch between Gregorian/Julian dates etc.
Plus I'd love to know your reasoning for the limitations and high accuracy requirement!
For all such matters see Calendrical Calculations (Google for it).
Oh, and there was no year 0 AD, the calendar went from 1BC to 1AD, or rather, we modern westerners define the calendar that way, at the time most of the world was using other systems.
Or, make calls to on-line calculators such as this one and save yourself a lot of time.
Some languages and databases do date arithmetic, some don't. If you store your dates in a database, try postgres :
pg=> SELECT now() - 'January 8, 52 BC'::DATE;
-----------------------------
754835 days 20:27:31.223035
If you don't use a DB, then it gets a bit more problematic. PHP's date arithmetic is ... well, I'd rather not talk about it. Python's is very good, but it starts at year 1BC.
You might have to roll your own...
why don't you subtract the timestamps?
mktime(16,59,0,8,7,2001) - mktime(16,59,0,8,7,2000) = seconds between them
If you need your web application to translate between timezones on a per-user basis, why not use TIMESTAMP across the board for all date/time fields? Consider that TIMESTAMP values are stored in UTC and converted to the timezone set for the connection when retrieved.
I have asked this question on IRC, read the MySQL documentation, searched Google extensively, and asked my co-workers, and I have yet to find a compelling reason to not use TIMESTAMP.
Note: I understand TIMESTAMP has a limited range of 1970 - 2038; that is not going to be an issue in my case. Also, I am using PHP with MySQL.
DATETIME is for arbitrary dates and times that you utilize in your data.
TIMESTAMP is for when you want the time to be automatically updated. If you want to know when the row was inserted/updated, use a TIMESTAMP.
Also, keep in mind that a TIMESTAMP is only stored in UTC -- it is converted to the local timezone of the server before it is transmitted back as part of a query.
In your case, you're better off using a DATETIME. If you're worried about UTC, that's fine -- just create your dates in UTC rather than using the local time. Use UTC_TIMESTAMP.
I think your answer is here:
I understand TIMESTAMP has a limited range of 1970 - 2038; that is not going to be an issue in my case.
I would be careful making assumptions about the longevity of projects especially when it comes to database schemas. Databases have a tendency to remain in place and in use long after the applications that used them have gone away.
Randalpho's answer is wrong on many facts!
Timestamps do not need to be automatically updated on creation OR updates.
Also, timestamps are translated to the CLIENT's local time, not the serever's.
Just look at the MySQL docs for datetime.