Finding overlapping dates and times in MySQL
May 1st, 2008Quite often you end up in situations where you are required to check and see if one time period overlaps another time period. Probably the most common situation this occurs in is when you are building a booking system - be it for tables or cars or rooms.
You have a series of entries in a database with a start (date)time and an end (date)time and before adding a new record you need to check that it doesn’t overlap with another booking.
The solution is fairly simple but I always end up making a quick diagram on a piece of paper to check.

As you can see two time periods can either be sequential (i.e. there is no overlap at all) or they can overlap in one of four ways. Put this into a diagram and the solution becomes pretty obvious.
There is an overlap if end_time_1 > start_time_2 AND start_time_1 < end_time_2
| Time | start_1 | start_2 | end_1 | end_2 | end_1 > start_2 | start_1 < end_2 |
|---|---|---|---|---|---|---|
| 1 | 09:00 | 08:00 | 11:00 | 10:00 | true | true |
| 2 | 09:00 | 10:00 | 11:00 | 12:00 | true | true |
| 3 | 09:00 | 08:00 | 11:00 | 12:00 | true | true |
| 4 | 09:00 | 09:30 | 11:00 | 10:30 | true | true |
| 5 | 09:00 | 07:00 | 11:00 | 08:00 | false | true |
| 6 | 09:00 | 12:00 | 11:00 | 13:00 | true | false |
An example SQL query would be something like the one below but make sure your datetime formats are correct - in MySQL the default format is YYYY-MM-DD hh:mm:ss
SELECT * FROM bookings WHERE room_id = '" . $room_id . "' AND ((date_end > '" . $start_date . "') AND (date_start < '" . $end_date . "')) ";
The above query will pull back the records where the times overlap.
blinks.org.uk
April 17th, 2008Lately I’ve have taken a little bit of time out from Art-Thing and have been working on a smaller side project called www.blinks.org.uk
I’ve been using this as a bit of a test bed for various aspects of Art-Thing but it is also a fun little project in its own right. AND even better it should be ready very soon, it is a directory of UK businesses and services with a pretty flat structure based on tagging and regions. Fast, easy to use and fun (if a business directory can be fun).
The site is almost ready to launch and the whole process from the first ideas until now has been very quick - it is built in CakePHP 1.2 and jQuery which make coding a pleasure again. It’s also fun to do a bit of design for a change instead of just the stuff under the hood.
Here is a sneak preview:

If you own or manage a business in the UK why not sign up for FREE with blinks.org.uk and see how it can help your business.
blinks.org.uk is a brand new directory of businesses and services based in the UK.
Every entry in the directory is approved by a real person and businesses have to provide their actual address so the directory is completely spam free and only contains quality listings.
- Link back to your website (great for SEO)
- Add a description of your business or service
- Add an image or company logo
- Update your entry whenever you want
- Add you business or service to multiple categories
- Add tags (keywords) - that are right just for you
- Automatically show your location on our map

CakePHP Calendar Helper
April 8th, 2008About six months ago I wrote a post about a Simple PHP calendar function I had written and how it was also really easy to use as a CakePHP helper.

I didn’t actually write the calendar specifically with Cake in mind, but I was working on a Cake site at the same time and I had a flash of inspiration. I was working on a project that needed a calendar, so I looked through all my old code but all the Calendars I had were all tied up in a terrible mess with bits of logic and SQL queries and layout all rolled into one. I looked on Google and still couldn’t find anything really easy to use - I wanted something I could just drop into place.
I suddenly realised that the way to do it was to stop trying to put any decision making into the calendar at all. The calendar only needs to display the right layout for the month and manage back and forward links. I decided to just dump the data in an array where the index corresponded to the day number (1 to 31) - the idea being that you can put anything in the array - plain text, html, javascript hooks for ajax etc.
It was in part influenced by some work I was doing using the The Yahoo! User Interface Library (YUI)
but I am very dubious about the whole notion of creating embedded calendars solely through Javascript when it could far more easily be done server side. (There is clearly a place for Javascript pop up calendars e.g. date pickers - I’m particularly fond of Marc Grabanski and Keith Woods’ version jQuery UI Datepicker)
At the time I had just moved over to using CakePHP as the main vehicle for my development work and it was clearly a great fit with the MVC setup of CakePHP - the calendar is just a shell that shows whatever you pour into it.
This is the first time I have had to go back and revisit the code, I have fixed the bugs, added some comments and set up a working example. At the moment all the logic is just sitting in the controller - but I am working on a component to tidy everything up and make it nice and portable (watch this space).
Thanks to everybody who commented or emailed me about the first version in September.
Calendar Helper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | <?php /** * Calendar Helper for CakePHP * * Copyright 2007-2008 John Elliott * Licensed under The MIT License * Redistributions of files must retain the above copyright notice. * * * @author John Elliott * @copyright 2008 John Elliott * @link http://www.flipflops.org More Information * @license http://www.opensource.org/licenses/mit-license.php The MIT License * */ class CalendarHelper extends Helper { var $helpers = array('Html', 'Form'); /** * Generates a Calendar for the specified by the month and year params and populates it with the content of the data array * * @param $year string * @param $month string * @param $data array * @param $base_url * @return string - HTML code to display calendar in view * */ function calendar($year = '', $month = '', $data = '', $base_url ='') { $str = ''; $month_list = array('january', 'febuary', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'); $day_list = array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'); $day = 1; $today = 0; if($year == '' || $month == '') { // just use current yeear & month $year = date('Y'); $month = date('M'); } $flag = 0; for($i = 0; $i < 12; $i++) { if(strtolower($month) == $month_list[$i]) { if(intval($year) != 0) { $flag = 1; $month_num = $i + 1; break; } } } if($flag == 0) { $year = date('Y'); $month = date('F'); $month_num = date('m'); } $next_year = $year; $prev_year = $year; $next_month = intval($month_num) + 1; $prev_month = intval($month_num) - 1; if($next_month == 13) { $next_month = 'january'; $next_year = intval($year) + 1; } else { $next_month = $month_list[$next_month -1]; } if($prev_month == 0) { $prev_month = 'december'; $prev_year = intval($year) - 1; } else { $prev_month = $month_list[$prev_month - 1]; } if($year == date('Y') && strtolower($month) == strtolower(date('F'))) { // set the flag that shows todays date but only in the current month - not past or future... $today = date('j'); } $days_in_month = date("t", mktime(0, 0, 0, $month_num, 1, $year)); $first_day_in_month = date('D', mktime(0,0,0, $month_num, 1, $year)); $str .= '<table class="calendar">'; $str .= '<thead>'; $str .= '<tr><th class="cell-prev">'; $str .= $this->Html->link(__('prev', true), 'calendar/' . $prev_year . '/' . $prev_month); $str .= '</th><th colspan="5">' . ucfirst($month) . ' ' . $year . '</th><th class="cell-next">'; $str .= $this->Html->link(__('next', true), 'calendar/' . $next_year . '/' . $next_month); $str .= '</th></tr>'; $str .= '<tr>'; for($i = 0; $i < 7;$i++) { $str .= '<th class="cell-header">' . $day_list[$i] . '</th>'; } $str .= '</tr>'; $str .= '</thead>'; $str .= '<tbody>'; while($day <= $days_in_month) { $str .= '<tr>'; for($i = 0; $i < 7; $i ++) { $cell = ' '; if(isset($data[$day])) { $cell = $data[$day]; } $class = ''; if($i > 4) { $class = ' class="cell-weekend" '; } if($day == $today) { $class = ' class="cell-today" '; } if(($first_day_in_month == $day_list[$i] || $day > 1) && ($day <= $days_in_month)) { $str .= '<td ' . $class . '><div class="cell-number">' . $day . '</div><div class="cell-data">' . $cell . '</div></td>'; $day++; } else { $str .= '<td ' . $class . '> </td>'; } } $str .= '</tr>'; } $str .= '</tbody>'; $str .= '</table>'; return $str; } } ?> |
Calendar Controller
The controller is responsible for creating the data array containing the calendar ‘events’ and then passing this on to the view from where the calendar is called.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | <?php /** * Example controller for the Calendar Helper * * Copyright 2008 John Elliott * Licensed under The MIT License * Redistributions of files must retain the above copyright notice. * * * @author John Elliott * @copyright 2008 John Elliott * @link http://www.flipflops.org More Information * @license http://www.opensource.org/licenses/mit-license.php The MIT License * */ uses('sanitize'); class EventsController extends AppController { var $name = 'Events'; var $helpers = array('Html', 'Form', 'Calendar'); /** * the idea is that the calendar helper itself is purely a shell * the calendar will just display whatever is sent to it * anything you want to do to it is put togthere here in the controller or in a component when I get around to writing it * * @param $year string * @param $month string * **/ function calendar($year = null, $month = null) { $this->Event->recursive = 0; $month_list = array('january', 'febuary', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'); $day_list = array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'); $base_url = $this->webroot . 'events/calendar'; // NOT not used in the current helper version but used in the data array $view_base_url = $this->webroot. 'events'; $data = null; if(!$year || !$month) { $year = date('Y'); $month = date('M'); $month_num = date('n'); $item = null; } $flag = 0; for($i = 0; $i < 12; $i++) { // check the month is valid if set if(strtolower($month) == $month_list[$i]) { if(intval($year) != 0) { $flag = 1; $month_num = $i + 1; $month_name = $month_list[$i]; break; } } } if($flag == 0) { // if no date set, then use the default values $year = date('Y'); $month = date('M'); $month_name = date('F'); $month_num = date('m'); } $fields = array('id', 'name', 'DAY(event_date) AS event_day'); $var = $this->Event->findAll('MONTH(Event.event_date) = ' . $month_num . ' AND YEAR(Event.event_date) = ' . $year, $fields, 'Event.event_date ASC'); /** * loop through the returned data and build an array of 'events' that is passes to the view * array key is the day of month * */ foreach($var as $v) { if(isset($v[0]['event_day'])) { $day = $v[0]['event_day']; if(isset($data[$day])) { $data[$day] .= '<br /><a href="' . $view_base_url . '/view/' . $v['Event']['id'] . '">' . $v['Event']['name'] . '</a>'; } else { $data[$day] = '<a href="' . $view_base_url . '/view/' . $v['Event']['id'] . '">' . $v['Event']['name'] . '</a>'; } } } $this->set('year', $year); $this->set('month', $month); $this->set('base_url', $base_url); $this->set('data', $data); } } ?> |
Event Model
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <?php class Event extends AppModel { var $name = 'Event'; var $useTable = 'events'; var $validate = array( 'name' => array( 'rule' => array('minLength', 2), 'message' => 'Name must be at least 2 characters long', 'required' => true ), 'notes' => array( 'rule' => array('minLength', 2), 'message' => 'Please add some notes', 'required' => true ), ); } ?> |
Calendar View
1 2 3 4 5 6 7 8 9 | <h2><?php __('Events');?></h2> <?php echo $calendar->calendar($year, $month, $data, $base_url); ?> |
events SQL
1 2 3 4 5 6 7 8 9 10 | CREATE TABLE `events` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `event_date` datetime DEFAULT NULL, `notes` text, `created` datetime DEFAULT NULL, `modified` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=15 DEFAULT CHARSET=latin1; |
CSS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* calendar CSS */ table.calendar {width: auto; border: 1px solid #cccccc; border-collapse: collapse; margin: 0px; padding: 0px; background-color: #ffffff;} table.calendar th {background-color: #eeeeee; text-transform: none; color: #444444; padding: 4px; text-align: center; border: 1px solid #eeeeee;} table.calendar th.cell-prev {text-align: left;} table.calendar th.cell-next {text-align: right;} table.calendar th.cell-header {width: 70px; border-bottom: 1px solid #cccccc;} table.calendar td.cell-today {background-color: #e2e8f6;} /* today in the current month */ table.calendar td.cell-weekend {background-color: #F3F5EB;} table.calendar td {border: 1px solid #cccccc;} table.calendar td div.cell-number {text-align: right; font-size: 8px; color: #444444; display: block;} table.calendar td div {display: block; font-size: 10px; text-align: left;} table.calendar thead th {border: 1px solid #cccccc;} |
To Do List
I’m feeling a little less time poor at the moment and want to do a bit of work on this. If anybody has any comments or suggestions, please let me know. At the moment my plans are as follows (in no particular order).
- add support for internationalisation
- put the checking date checking (and possibly data array construction into a component)
- add built in AJAX support (haven’t decided on jQuery or Prototype yet though)
- look at using Cake 1.2 routes as part of date checking using regular expressions (how easy would it be to combine this with the internationalisation?)
Examples & Downloads
Check out the Working Calendar Helper Example
Download all the files calendar-helper.zip - this is a zipped copy of the app directory, just set up you database, edit /app/core/database.php and slot it into place. (Note Cake 1.2 only)
MySQL import / export at the Command Line
March 19th, 2008Like many (most?) developers when I work with a database I tend to manage them using another programme - usually either phpMyAdmin or Navicat. However there are times when you have to get basic again and dig down to the Command Line (usually because of an access issue like a firewall setting you can’t change or because you need to import a file too big for phpMyAdmin). The trouble is if you only use these commands once in a blue moon you soon forget them.
Dump (export your database)
- Login to the shell or Command Prompt, navigate to where you would like your file saved.
mysqldump --user=your_username --password=your_password your_database > your_dump_file.sql
Where:
your_username is a mysql user with the correct rights to the database you want to dump.
your_password is the password for your_username.
your_database is the name of your database.
your_dump_file.sql is the name of the file that will be created in the export.
Import
- Create the database that you want to import into, but leave it empty or if you are using an existing database remove the tables (make sure you have a backup first).
- Login to the shell or Command Prompt
mysql --user=your_username --password=your_password your_database < your_file_to_import.sql




