{"id":6476,"date":"2017-02-15T18:20:49","date_gmt":"2017-02-15T23:20:49","guid":{"rendered":"https:\/\/www.caskeys.com\/dc\/?p=6476"},"modified":"2026-05-18T11:30:39","modified_gmt":"2026-05-18T15:30:39","slug":"php-chronofix","status":"publish","type":"post","link":"https:\/\/www.caskeys.com\/dc\/php-chronofix\/","title":{"rendered":"PHP Chronofix"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Introduction<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">This self-contained library is intended to aid in parsing common date and time values across differing incoming formats, then output the result in a uniform format of your choice.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The simple fact is that client-side inputs are notoriously unreliable. Even when using native date and time fields, you may not end up with uniform results across browsers &#8211; or even from the same browser. This happens because some browsers normalize valid <code>datetime-local<\/code> values by omitting seconds when they are zero. Code that expects <code>Y-m-d H:i:s<\/code> may reject fully legitimate browser-submitted values unless the server normalizes them.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Google Chrome, for instance, may send a different format depending on the seconds value. Even if you enforce seconds using the <code>step<\/code> attribute, Chrome will not include seconds as part of the submitted date\/time string when the user chooses a seconds value of <code>00<\/code>. Choose a seconds value of <code>01<\/code> or greater, and Chrome <strong>will<\/strong> include the seconds component. Same browser. Same version. Same field attributes. Entirely different submitted formats depending on perfectly valid user input.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Correct? Yes, from an engineering standpoint. Practical? Not when you are just trying to parse a simple input and keep your hair.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/www.caskeys.com\/dc\/wp-content\/uploads\/2017\/02\/date_time_google.png\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"154\" src=\"https:\/\/www.caskeys.com\/dc\/wp-content\/uploads\/2017\/02\/date_time_google-300x154.png\" alt=\"\" class=\"wp-image-6496\" srcset=\"https:\/\/www.caskeys.com\/dc\/wp-content\/uploads\/2017\/02\/date_time_google-300x154.png 300w, https:\/\/www.caskeys.com\/dc\/wp-content\/uploads\/2017\/02\/date_time_google.png 486w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><figcaption class=\"wp-element-caption\">Unless you choose a seconds value of 01 or greater, Chrome simply won\u2019t include seconds.<\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">You could use text fields and invoke heavy JavaScript date\/time pickers, but that can harm the mobile experience, where seamless date selection is already built in. You could also use a dynamic solution that checks for native date\/time field support, but then you are right back to dealing with inconsistent formatting.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In a nutshell, failing to perform server-side validation may lead to unpredictable behavior in whatever code relies on the input. Databases are particularly finicky. Go ahead and send client-side dates directly to an RDBMS. Your results will be the same as Forrest Gump\u2019s chocolate box.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/www.caskeys.com\/dc\/wp-content\/uploads\/2017\/02\/image.png\"><img loading=\"lazy\" decoding=\"async\" width=\"347\" height=\"145\" src=\"https:\/\/www.caskeys.com\/dc\/wp-content\/uploads\/2017\/02\/image.png\" alt=\"You never know what you're going to get.\" class=\"wp-image-7922\" srcset=\"https:\/\/www.caskeys.com\/dc\/wp-content\/uploads\/2017\/02\/image.png 347w, https:\/\/www.caskeys.com\/dc\/wp-content\/uploads\/2017\/02\/image-300x125.png 300w\" sizes=\"auto, (max-width: 347px) 100vw, 347px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Unfortunately, many forms of server-side validation are themselves rather persnickety. In the example above, a validator expecting seconds may reject input from Chrome, along with several mobile browsers. This is where my date and time library comes into play. By leveraging a layered approach and PHP\u2019s <code>strtotime()<\/code> parsing, Chronofix can accept most valid time strings, verify them, and output a single uniform format for use.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Use<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Simple &#8211; Object is initialized with default settings:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: Code:; notranslate\" title=\"Code:\">\n\/\/ Initialize object with default settings.\n$dc_time \t\t= new dc\\Chronofix();\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Advanced &#8211; Initialize a settings object first, and apply it to the main object.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Code:; notranslate\" title=\"Code:\">\n\/\/ Initialize settings object, and use it\n\/\/ to set date format to Year-Month-Day only.\n$dc_time_settings = new dc\\Config();\n$dc_time_settings-&gt;set_format(&#039;Y-m-d&#039;); \n\n\/\/ Initialize time library with settings. $dc_time = new dc\\Chronofix($dc_time_settings);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Once initialized the following functions are exposed. All examples assume default settings.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Settings Object<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Again be aware settings are entirely optional.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: Code:; notranslate\" title=\"Code:\">\n\/\/ Outputs Y-m-d H:i:s\necho $settings-&gt;get_format();\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Returns the format string currently in use.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: Code:; notranslate\" title=\"Code:\">\n$string = &#039;Y-m-d H:i:s&#039;;\n\n$settings-&gt;set_format($string);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Replaces format in use with $string.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Time Object<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: Code:; notranslate\" title=\"Code:\">\n$object = $time-&gt;get_settings();\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Returns a reference to settings object in use by time object. By accessing the current settings object, you can modify settings at runtime.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: Code:; notranslate\" title=\"Code:\">\n\/\/ Outputs 2017-02-15 12:00:00\necho $time-&gt;get_time();\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Returns the current date\/time value as a string.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: Code:; notranslate\" title=\"Code:\">\n$string = &#039;2017-02-15 12:00:00&#039;;\n\n\/\/ Outputs TRUE if valid, or FALSE.\necho $time-&gt;is_valid($string);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">For internal use, but exposed for possible utility purposes. Evaluates $string against current date\/time format. If the formats match, TRUE is returned. Otherwise FALSE is returned.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: Code:; notranslate\" title=\"Code:\">\n\/\/ Outputs 2017-02-15 12:00:00\necho $time-&gt;sanitize();\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Evaluates the current date\/time value and attempts to convert its format to the current format setting. Leverages a combination of php&#8217;s <code>strtotime<\/code> and date object to handle nearly any format of dates and times. Outputs newly formatted date\/time string, or NULL on failure.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: Code:; notranslate\" title=\"Code:\">\n$object = new dc\\Config();\n\n$time-&gt;set_settings($object);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Replaces current settings object with <code>$object<\/code>.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: Code:; notranslate\" title=\"Code:\">\n$string = &#039;2017-02-15 12:00:00&#039;;\n\n$time-&gt;set_time($string);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Replaces the current date\/time string with $string. You will need to do this before performing any other operations.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Source<\/h1>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"alignleft\"><a href=\"https:\/\/github.com\/DCurrent\/chronofix\/releases\/latest\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"249\" src=\"https:\/\/www.caskeys.com\/dc\/wp-content\/uploads\/2017\/02\/logo-github-1-300x249.png\" alt=\"\" class=\"wp-image-6575\"\/><\/a><figcaption class=\"wp-element-caption\">Full source available on Github.<\/figcaption><\/figure>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>Universal date parse and formatting for PHP projects.<\/p>\n","protected":false},"author":1,"featured_media":6216,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":true,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[71],"tags":[299,269,234,298,286,238],"class_list":["post-6476","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-technology-temerity","tag-career-chaos","tag-applications-inspector-blair","tag-coding-php","tag-technology-temerity","tag-uk-ehs","tag-coding-web-development"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/www.caskeys.com\/dc\/wp-content\/uploads\/2016\/06\/logo-php.png","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p5lNM5-1Gs","jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/posts\/6476","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/comments?post=6476"}],"version-history":[{"count":29,"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/posts\/6476\/revisions"}],"predecessor-version":[{"id":7937,"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/posts\/6476\/revisions\/7937"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/media\/6216"}],"wp:attachment":[{"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/media?parent=6476"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/categories?post=6476"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/tags?post=6476"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}