PHP, Dates and Daylight Savings Time

2009 December 9

I am pretty sure that at some point in your programming career you will have to mess with dates.  This is normally not a big deal, as a date is a date is a date.  But then, you will get into more complicated date structures and algorithms involving timezones and daylight savings time.  This is about when your hair will start to fall out and you start running around like an idiot screaming at the walls.  I know, because I was doing almost this exact thing yesterday.

What happened:

I started with a date, made a timestamp, and then wanted to loop through all dates less than today.  I was doing some data scrubbing based on these dates.  The issue was that when I went to graph the data based on these dates, I was missing data for Oct 30 and March 11.  The more observant programmer, the person who read the title, or someone not blinded by their own code would have noticed that those are the days when we Americans celebrate Daylight savings (celebrate being a relative term).  Much like Y2K, DST causes many programmers much anguish.

For example, if I start looping from January 1, 2006 to today, my code looked something like this:

  1. $timestamp = 1136132724; //gmt for jan 01, 2006 + some hours
  2. //scrub the date to just the Year, month and day – scrub the hours, minutes and seconds off
  3. $date = date('Y-m-d', $timestamp);
  4. $minDate = strtotime($date);
  5. while ($minDate < time()) {
  6. //do some code
  7. //increment the date by 24hrs worth of seconds
  8. $minDate += 86400;
  9. }

By all accounts, whether this code is ugly or not, this loop will allow you to run some code for every day between the initial date and today. Except one thing, DST.

What happens is that on the code where we do this:

  1. $date = date('Y-m-d', $timestamp);

We are essentially asking for the same thing as:

  1. $date = date('Y-m-d 00:00:00', $timestamp);

or

  1. $date = date('Y-m-d', $timestamp).' 00:00:00';

Which is midnight of the day we are starting on.  Still, we should be fine, right?

Nope.

What happens here is that on October 29, 2006 when we add 86400 seconds, we do not get the timestamp of:

  1. 2006-10-30 00:00:00

we in fact get:

  1. 2006-10-29 23:00:00

because of DST. Fun, right!?

The Solution:

What we can do is actually initialize the original date variable to be at noon on the initial date.  This means that whether the time goes forward in the spring to 1pm, backwards to 11am, or stays at noon we are ALWAYS talking about the same day. Whereas, 11pm, 12am and 1am are not on the same days.

The code looks like this:

  1. $timestamp = 1136132724; //gmt for jan 01, 2006 + some hours
  2. //scrub the date to just the Year, month and day – scrub the hours, minutes and seconds off
  3. $date = date('Y-m-d', $timestamp);
  4. $minDate = (strtotime($date) + 43200);
  5. while ($minDate < time()) {
  6. //do some code
  7. //increment the date by 24hrs worth of seconds
  8. $minDate += 86400;
  9. }

Where we essentially just added 12 hours to the scrubbed date. This gives us exactly 12pm.

Caveats:

This code sort of assumes that all of your timestamps were recorded in the same time zone. Between PHP and MySQL you can get some squirley date issues.  The best solution here is to record all timestamps in GMT and then adjust them in one place only, either as you pull them from MySQL or in the PHP. DO NOT try to adjust sometimes in one place and other times in the other, it is too easy to get confused.

The other thing to realize is that your users may be pulling data from across the globe, which means that the timezones are way different. This also means that 12pm your time may be 12am their time, which can put you in the same predicament.  I believe it is better to run date-based system critical data in a single timezone and do not run it from random or different timezones, just in case.

Questions, Comments, Suggestions? Please leave them as a comment below this post!

Sphere: Related Content

MySQL: Convert UNIX_TIMESTAMP to UTC DATETIME

2009 November 17

We just learned that when you insert a UNIX_TIMESTAMP into MySQL that it will keep the UTC version of the timestamp, which is good.  However, when you use FROM_UNIXTIME() to convert your Unix timestamp into a datetime string, it will localize the datetime to mysql’s timezone.

So, a couple things here:

  1. System time and MySQL time are not always the same
  2. UTC and MySQL time are not the same
  3. UNIX_TIMESTAMP() is not the same actual time as FROM_UNIXTIME(UNIX_TIMESTAMP())

So, there is actually a somewhat easy solution (once you know it) to fix this issue.

MySQL provides a CONVERT_TZ(datetime, from, to) function.

Our first solution was to just get the timezone of the server and drop that into the code:

  1. CONVERT_TZ(DATETIME, 'MST', '+00:00')

This does not work if we do and install on a server not running on MST.  So, the better solution is:

  1. CONVERT_TZ(DATETIME, @@global.time_zone, '+00:00')

The variable “@@global.time_zone” is a MySQL system variable which will return the timezone MySQL is running on.  With this, we have now just converted ALL of our datetimes to UTC time, and then we can adjust them to our users as we wish.

If you wanted to pass the user’s timezone into the function, you would just need to know the UTC offset and replace ‘+00:00′ with that offset.

I.E. MST would be “-07:00″

Sphere: Related Content

Public/Private Keys for SSH Authentication

2009 October 26

Most of this information comes from here: HowTos/Network/Securing SSH I have taken the liberty to cut out the extra stuff, and reorganize the information a little bit.

Definitions:

Client – The computer you use to connect to the server

Server – The computer/server you are connecting to via SSH

Client Steps:

Get to your user directory by typing:

  1. $ cd ~/

Once you are there, verify that you do not already have an “.ssh” directory, if you do not create it by typing:

  1. $ mkdir .ssh

Now you want to set up the key you will use to authenticate yourself to the server, type:

  1. $ ssh-keygen -t rsa

When this is running, it will ask you for a passphrase, and other settings. You should be able to just hit the enter key through the prompts. This way you do not have to enter a password at all when you run the alias you will set up (this will be explained in a minute).
Once finished running, this last command will create two files, id_rsa and id_rsa.pub in your .ssh directory. These files identify you to the server.
At this point, you need to tell the server who you are by adding yourself to the servers ‘Authenticated users’ list. You do this by copying your id_rsa.pub file to the server.

  1. $ scp .ssh/id_rsa.pub user@server.com:/user/

Note: Be sure to replace the words “user” and “server” appropriately in the command above.

Open your .profile (or .bash_profile) file for editing:

  1. $ nano .profile

Add the following to your .profile file or .bash_profile file to have an alias for your server:

  1. alias servername="ssh user@server.com"

Note: replace the words to match your server/user

Make sure your current bash shell has the current version of your profile file (replace with correct file):

  1. $ source .profile

Server Steps:

Once you have SSHed into your server the old fashioned way, you will need to add yourself to the authenticated users list.
Make sure you are in the user’s root directory:

  1. $ cat id_rsa.pub >> .ssh/authorized_keys

Make sure you have a .ssh folder, if not create it (see above).
Now, add the content of the id_rsa.pub file to the authenticated_keys file in .ssh. If the file exists, this command will concatenate the content of id_rsa.pub to the file. If the file does not exist yet, it will after you run this command:

  1. $ chmod 700 .ssh
  2. $ chmod 600 .ssh/authenticated_keys

Once you have concatenated the data, you are almost ready to go. Just make sure the files have the correct permissions:

  1. $ exit

Now, exit out of your ssh session:

  1. $ servername

Test your Authentication:

To test, just type the name of the alias you set up, should be where you replaced the word “servername” in the alias definition you created earlier:

  1.  

This should send you straight through to the server. Voila!

Sphere: Related Content

Does PHP pass objects by reference?

2009 September 17

I needed to know if PHP passes objects by reference, because I wanted to create some reciprocal code that would be REALLY messy if it did not.

The steps:

  1. Instantiate both objects
  2. Add the second ($two) object to the first ($one)
  3. Modify the second object outside of $one after adding it
  4. Add data to $two from inside $one
  5. Render the objects and see if the data that was added to $two outside of $onw was added to the $two stored in $one (confused?)
  6. Also, check that the data added to $two from inside of $one was set on $two

If objects are being passed by reference, then any change you make on $two whether inside the $one object or on the original $two object will be refleced when you output the individual objects separately. (i.e. they will output exactly the same)

If the objects are copied and therefore not passed by reference, then you will see that the output of the individual objects is completely different.

Here is the code:

  1. class one
  2. {
  3.    protected $dataObj;
  4.    public function addData($data)
  5.    {
  6.       $this->dataObj = $data;
  7.    }
  8.  
  9.    public function __toString()
  10.    {
  11.       $this->dataObj->addData('c', 'what!?');
  12.       ob_start();
  13.       echo $this->dataObj;
  14.       return ob_get_clean();
  15.    }
  16. }
  17.  
  18. class two
  19. {
  20.    protected $data = array('a' => 5);
  21.    public function addData($index, $val)
  22.    {
  23.       $this->data[$index] = $val;
  24.    }
  25.  
  26.    public function __toString()
  27.    {
  28.       ob_start();
  29.       var_dump($this->data);
  30.       return ob_get_clean();
  31.    }
  32. }
  33.  
  34. $one = new one();
  35. $two = new two();
  36.  
  37. $one->addData($two);
  38.  
  39. $two->addData('b', 'howdy');
  40.  
  41. echo $one;
  42. echo $two;

So…what was the result?

  1. array
  2.   'a' => int 5
  3.   'b' => string 'howdy' (length=5)
  4.   'c' => string 'what!?' (length=6)
  5.  
  6. array
  7.   'a' => int 5
  8.   'b' => string 'howdy' (length=5)
  9.   'c' => string 'what!?' (length=6)

They were exactly the same, which means that PHP passed the $two object by reference to $one. This is a cool feature because it means you can do some really cool things with objects and allows you to be defensive with your programming if someone does something out of order. There are some potential issues if your developers think that they are NOT passed by reference and that they are modifying a different $two than the one in the object. Good comments should fix that.

Sphere: Related Content

.Net Compact Framework – Sets the locale for you

2009 August 10

When you are developing in the .Net Compact Framework and try to output things like date, time, or any numbers you should take care to pay attention to the device’s locale.  The reason is that in some countries they use “.” for decimals and in others they use “,”.  There are other differences too, like how dates are formatted internationally.

The solution here, if you need to ALWAYS output data in your specific format, is to pass in an “Invariant Culture” to the string output like so:

  1. *Time.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);

(where *Time is your time variable)

Sphere: Related Content

Slashes issues

2009 August 5

I think that at some point, every PHP developer comes head to head with 2 issues, and probably at the same time.

  1. magic_quotes_gpc
  2. different servers having different setups

My solution for this was to use stripslashes() on a file path, example:

  1. //with magic_quotes_gpc on $path looks like: "mydomain.com//path//to//file"
  2. $path = stripslashes($path);
  3. //now it looks like: "mydomain.com/path/to/file"

This is great, if your file paths look like that, and you know that magic quotes is on. BUT, if you move your code to a server where it is not on, or you run stripslashes on a path that is already clean, you end up with this:

  1. //clean $path looks like: "mydomain.com/path/to/file"
  2. $path = stripslashes($path);
  3. //now it looks like: "mydomain.compathtofile" <- that does not look right!

So, the better solution to stripslashes() is something like this:

  1. function cleanFilePath($path)
  2. {
  3. //check if magic_quotes_gpc is on or 1
  4.    if ((ini_get('magic_quotes_gpc') == '1' || strtolower(ini_get('magic_quotes_gpc')) == 'on')) {
  5.       //if you see a double backslash, replace it with a single
  6.        if (strpos($file, '\\\\') !== false) {
  7.           $path = str_replace('\\\\', '\\', $path);
  8.        }
  9.        //if you see a double forward slash, replace it with a single
  10.        if (strpos($file, '//') !== false) {
  11.            $path = str_replace('//', '/', $path);
  12.        }
  13.  
  14.    }
  15.   return $path;
  16. }

Now, there is one more thing. If your paths have “http://”, “ftp://”, “file://” or any other prefix, you will need to take these off of the string and make a note of what it was, then clean the path and put the prefix back on. Otherwise, the “//” on the prefix will be removed by the script and your path won’t work.

Sphere: Related Content

Steal an inline onclick event from one element to another

2009 March 26

Sometimes, someone writes a piece of HTML with inline JS (naughty naughty). And sometimes, you need to use that same functionality elsewhere in your document, but it is named dynamically so you can’t just copy/paste.

Here comes Prototype to the rescue.

You can do this:

  1. var oldItem = 'oldItem';
  2. var itemToGetEvent = 'newItem';
  3. var temp = $(itemToGetEvent).observe('click', function(){
  4.    eval($('oldItem').readAttribute('onclick'));
  5. });

olditem is the item that has the onclick attribute inline
newitem is the item that needs to get this onclick attribute

I am just copying the code and then setting a listener on the new item so that it mimics the onclick attribute of the other item.

Another Suggestion:

  1. <h1 onclick="this.innerHTML='foobar';">clickme</h1>
  2. <h1>clickme2</h1>
  3. <script>
  4.  var h = document.getElementsByTagName('h1');
  5.  h[1].onclick = function(ev) {
  6.    h[0].onclick.call(this, ev);
  7.  }
  8. </script>
Sphere: Related Content

Keep Prototype’s periodical executor from running forever

2009 March 12

Every once in a while, it is nice to use PeriodicalExecutor from Prototype.js, becuase you just don’t know when something will happen, or when something will be in the DOM.  Maybe you are the master at JS timing, but I’m not so here is what I do.

When I know that there is a possibility that a DOM element, say id=”firstName”, will be in the DOM soon or might never be in the DOM.  I will call PeriodicalExecutor and then put in a counter.  Like so:

  1.   var tempPeCounter = 0;
  2.   new PeriodicalExecuter(function(pe) {
  3.     if (tempPeCounter == 50) {
  4.       pe.stop();
  5.     }
  6.  
  7.     if ($('firstName')) {
  8.       pe.stop();
  9.      $('firstName').focus();
  10.     }
  11.  
  12.     tempPeCounter++;
  13. }, .1);

What will happen is, if the element shows up in the first 50 iterations (here it would be in the first 5 seconds), it will get focus. Otherwise, the counter will increment away until it stops the PeriodicalExecutor.  This is a nice way to make sure that your JS doesn’t eat up too many resources and to guarantee that your PeriodicalExecutor stops at some point.

Note/Bonus: I have no idea why a field or Element called “firstName” would not be in the DOM.  I guess, if I was going to use “firstName” it would probably always be there, but this is hypothetical, right?

Sphere: Related Content

Government Time Servers down, a sign of bad times?

2009 March 9

If you have an electronics device whose time is all jacked and it normally updates all on its own, then you are probably using one of the government time servers.  Now, the fun part!

A bunch of them are completely overloaded. (see picture)

nist-internet-time-service-clock

If you choose one of the other lesser known servers your time will update automagically and you won’t be missing all of your meetings.

Sphere: Related Content

Windows mobile not updating time after daylight savings DST update

2009 March 9

Updating Windows Mobile phones for Daylight Saving Time

If you are having issues with you windows mobile device and Pocket PC and the daylight savings(DST) change then you probably need to follow the Micorsoft update procedure here:

http://www.microsoft.com/windowsmobile/en-us/downloads/microsoft/daylight-savings-update.mspx

or you can download the CAB file here:

Update for Windows Mobile (KB949168)

Sphere: Related Content