From ac4b84765bb72502d4250abf7c066ba4662b5a8a Mon Sep 17 00:00:00 2001
From: Manuel Cillero
Date: Wed, 26 Jul 2017 14:11:39 +0200
Subject: [PATCH] New module 'Date'
---
sites/all/modules/date/CHANGELOG.txt | 795 ++++
sites/all/modules/date/INSTALL.txt | 71 +
sites/all/modules/date/LICENSE.txt | 339 ++
sites/all/modules/date/README.txt | 307 ++
sites/all/modules/date/date-rtl.css | 33 +
sites/all/modules/date/date.css | 206 ++
sites/all/modules/date/date/date.info | 13 +
sites/all/modules/date/date/date.install | 457 +++
sites/all/modules/date/date/date.module | 887 +++++
sites/all/modules/date/date/date.theme | 283 ++
.../all/modules/date/date/date.theme.original | 282 ++
sites/all/modules/date/date/date.views.inc | 18 +
.../modules/date/date/date.views_convert.inc | 87 +
sites/all/modules/date/date/date_admin.inc | 717 ++++
.../date/date/date_content_generate.inc | 185 +
sites/all/modules/date/date/date_elements.inc | 586 +++
.../date/date/date_handler_field_multiple.inc | 186 +
sites/all/modules/date/date/date_repeat.inc | 209 ++
sites/all/modules/date/date/date_token.inc | 97 +
sites/all/modules/date/date_api.admin.inc | 249 ++
sites/all/modules/date/date_api.info | 11 +
sites/all/modules/date/date_api.install | 508 +++
sites/all/modules/date/date_api.js | 21 +
sites/all/modules/date/date_api.module | 2826 ++++++++++++++
sites/all/modules/date/date_api_elements.inc | 634 ++++
.../modules/date/date_api_formats_list.inc | 192 +
sites/all/modules/date/date_api_ical.inc | 802 ++++
sites/all/modules/date/date_api_sql.inc | 881 +++++
.../modules/date/date_locale/date_locale.info | 13 +
.../date/date_locale/date_locale.module | 295 ++
.../all/modules/date/date_php4/date_php4.inc | 1071 ++++++
.../all/modules/date/date_php4/date_php4.info | 12 +
.../modules/date/date_php4/date_php4.install | 16 +
.../modules/date/date_php4/date_php4.module | 60 +
.../modules/date/date_php4/date_php4_calc.inc | 1498 ++++++++
.../modules/date/date_php4/date_php4_lib.inc | 442 +++
.../date/date_php4/date_php4_missing_data.inc | 66 +
.../date_php4_tz_abbreviations_list.inc | 10 +
.../date/date_php4/date_php4_tz_create.inc | 3254 +++++++++++++++++
.../date_php4/date_php4_tz_identifiers.inc | 11 +
.../date/date_php4/date_php4_tz_map.inc | 6 +
.../modules/date/date_popup/date_popup.info | 15 +
.../date/date_popup/date_popup.install | 120 +
.../all/modules/date/date_popup/date_popup.js | 33 +
.../modules/date/date_popup/date_popup.module | 685 ++++
.../date_popup/lib/jquery.timeentry.pack.js | 7 +
.../date/date_popup/themes/calendar.css | 166 +
.../date/date_popup/themes/datepicker.1.7.css | 58 +
.../date/date_popup/themes/datepicker.css | 137 +
.../themes/images/222222_7x7_arrow_left.gif | Bin 0 -> 53 bytes
.../themes/images/222222_7x7_arrow_right.gif | Bin 0 -> 53 bytes
.../themes/images/454545_7x7_arrow_left.gif | Bin 0 -> 53 bytes
.../themes/images/454545_7x7_arrow_right.gif | Bin 0 -> 53 bytes
.../themes/images/888888_7x7_arrow_left.gif | Bin 0 -> 53 bytes
.../themes/images/888888_7x7_arrow_right.gif | Bin 0 -> 53 bytes
.../dadada_40x100_textures_02_glass_75.png | Bin 0 -> 214 bytes
.../e6e6e6_40x100_textures_02_glass_75.png | Bin 0 -> 211 bytes
.../ffffff_40x100_textures_02_glass_65.png | Bin 0 -> 207 bytes
.../date_popup/themes/jquery.timeentry.css | 8 +
.../date/date_popup/themes/timeentry.css | 17 +
.../modules/date/date_repeat/date_repeat.info | 11 +
.../date/date_repeat/date_repeat.install | 62 +
.../date/date_repeat/date_repeat.module | 306 ++
.../date/date_repeat/date_repeat_calc.inc | 581 +++
.../date/date_repeat/date_repeat_form.inc | 407 +++
.../date/date_timezone/date_timezone.info | 12 +
.../date/date_timezone/date_timezone.install | 606 +++
.../date/date_timezone/date_timezone.js | 47 +
.../date/date_timezone/date_timezone.module | 289 ++
.../modules/date/date_tools/date_field.php | 142 +
.../date_tools/date_tools.change_type.inc | 171 +
.../date/date_tools/date_tools.event.inc | 388 ++
.../modules/date/date_tools/date_tools.info | 12 +
.../modules/date/date_tools/date_tools.module | 173 +
.../date/date_tools/date_tools.wizard.inc | 527 +++
.../modules/date/help/date-api-functions.html | 137 +
sites/all/modules/date/help/date-api.html | 23 +
.../all/modules/date/help/date-argument.html | 31 +
sites/all/modules/date/help/date-copy.html | 13 +
sites/all/modules/date/help/date-create.html | 21 +
sites/all/modules/date/help/date-display.html | 59 +
sites/all/modules/date/help/date-filter.html | 1 +
sites/all/modules/date/help/date-php4.html | 41 +
.../modules/date/help/date-repeat-form.html | 8 +
.../all/modules/date/help/date-timezones.html | 447 +++
sites/all/modules/date/help/date-types.html | 39 +
.../modules/date/help/date-views-dates.html | 45 +
sites/all/modules/date/help/date-views.html | 0
sites/all/modules/date/help/date.html | 2 +
sites/all/modules/date/help/date_api.help.ini | 90 +
sites/all/modules/date/help/embedding.html | 16 +
.../all/modules/date/help/form-elements.html | 50 +
sites/all/modules/date/help/new-features.html | 11 +
sites/all/modules/date/help/overview.html | 2 +
sites/all/modules/date/images/calendar.png | Bin 0 -> 440 bytes
sites/all/modules/date/images/ical16x16.gif | Bin 0 -> 357 bytes
.../modules/date/includes/date_api.views.inc | 266 ++
.../date/includes/date_api.views_default.inc | 98 +
.../includes/date_api_argument_handler.inc | 398 ++
.../modules/date/includes/date_api_fields.inc | 179 +
.../date/includes/date_api_filter_handler.inc | 617 ++++
.../includes/date_navigation_plugin_style.inc | 68 +
.../date_plugin_display_attachment.inc | 39 +
sites/all/modules/date/tests/README.txt | 19 +
sites/all/modules/date/tests/USHolidays.ics | 2029 ++++++++++
sites/all/modules/date/tests/Yahoo.csv | 16 +
sites/all/modules/date/tests/date.test | 146 +
sites/all/modules/date/tests/date_api.test | 414 +++
sites/all/modules/date/tests/date_repeat.test | 447 +++
sites/all/modules/date/tests/rrule.ics | 125 +
.../date/theme/date-navigation.tpl.php | 48 +
.../modules/date/theme/date-valarm.tpl.php | 40 +
.../modules/date/theme/date-vcalendar.tpl.php | 31 +
.../modules/date/theme/date-vevent.tpl.php | 47 +
.../date/theme/date-views-filter-form.tpl.php | 54 +
sites/all/modules/date/theme/theme.inc | 417 +++
116 files changed, 30150 insertions(+)
create mode 100644 sites/all/modules/date/CHANGELOG.txt
create mode 100644 sites/all/modules/date/INSTALL.txt
create mode 100644 sites/all/modules/date/LICENSE.txt
create mode 100644 sites/all/modules/date/README.txt
create mode 100644 sites/all/modules/date/date-rtl.css
create mode 100644 sites/all/modules/date/date.css
create mode 100644 sites/all/modules/date/date/date.info
create mode 100644 sites/all/modules/date/date/date.install
create mode 100644 sites/all/modules/date/date/date.module
create mode 100644 sites/all/modules/date/date/date.theme
create mode 100644 sites/all/modules/date/date/date.theme.original
create mode 100644 sites/all/modules/date/date/date.views.inc
create mode 100644 sites/all/modules/date/date/date.views_convert.inc
create mode 100644 sites/all/modules/date/date/date_admin.inc
create mode 100644 sites/all/modules/date/date/date_content_generate.inc
create mode 100644 sites/all/modules/date/date/date_elements.inc
create mode 100644 sites/all/modules/date/date/date_handler_field_multiple.inc
create mode 100644 sites/all/modules/date/date/date_repeat.inc
create mode 100644 sites/all/modules/date/date/date_token.inc
create mode 100644 sites/all/modules/date/date_api.admin.inc
create mode 100644 sites/all/modules/date/date_api.info
create mode 100644 sites/all/modules/date/date_api.install
create mode 100644 sites/all/modules/date/date_api.js
create mode 100644 sites/all/modules/date/date_api.module
create mode 100644 sites/all/modules/date/date_api_elements.inc
create mode 100644 sites/all/modules/date/date_api_formats_list.inc
create mode 100644 sites/all/modules/date/date_api_ical.inc
create mode 100644 sites/all/modules/date/date_api_sql.inc
create mode 100644 sites/all/modules/date/date_locale/date_locale.info
create mode 100644 sites/all/modules/date/date_locale/date_locale.module
create mode 100644 sites/all/modules/date/date_php4/date_php4.inc
create mode 100644 sites/all/modules/date/date_php4/date_php4.info
create mode 100644 sites/all/modules/date/date_php4/date_php4.install
create mode 100644 sites/all/modules/date/date_php4/date_php4.module
create mode 100644 sites/all/modules/date/date_php4/date_php4_calc.inc
create mode 100644 sites/all/modules/date/date_php4/date_php4_lib.inc
create mode 100644 sites/all/modules/date/date_php4/date_php4_missing_data.inc
create mode 100644 sites/all/modules/date/date_php4/date_php4_tz_abbreviations_list.inc
create mode 100644 sites/all/modules/date/date_php4/date_php4_tz_create.inc
create mode 100644 sites/all/modules/date/date_php4/date_php4_tz_identifiers.inc
create mode 100644 sites/all/modules/date/date_php4/date_php4_tz_map.inc
create mode 100644 sites/all/modules/date/date_popup/date_popup.info
create mode 100644 sites/all/modules/date/date_popup/date_popup.install
create mode 100644 sites/all/modules/date/date_popup/date_popup.js
create mode 100644 sites/all/modules/date/date_popup/date_popup.module
create mode 100644 sites/all/modules/date/date_popup/lib/jquery.timeentry.pack.js
create mode 100644 sites/all/modules/date/date_popup/themes/calendar.css
create mode 100644 sites/all/modules/date/date_popup/themes/datepicker.1.7.css
create mode 100644 sites/all/modules/date/date_popup/themes/datepicker.css
create mode 100644 sites/all/modules/date/date_popup/themes/images/222222_7x7_arrow_left.gif
create mode 100644 sites/all/modules/date/date_popup/themes/images/222222_7x7_arrow_right.gif
create mode 100644 sites/all/modules/date/date_popup/themes/images/454545_7x7_arrow_left.gif
create mode 100644 sites/all/modules/date/date_popup/themes/images/454545_7x7_arrow_right.gif
create mode 100644 sites/all/modules/date/date_popup/themes/images/888888_7x7_arrow_left.gif
create mode 100644 sites/all/modules/date/date_popup/themes/images/888888_7x7_arrow_right.gif
create mode 100644 sites/all/modules/date/date_popup/themes/images/dadada_40x100_textures_02_glass_75.png
create mode 100644 sites/all/modules/date/date_popup/themes/images/e6e6e6_40x100_textures_02_glass_75.png
create mode 100644 sites/all/modules/date/date_popup/themes/images/ffffff_40x100_textures_02_glass_65.png
create mode 100644 sites/all/modules/date/date_popup/themes/jquery.timeentry.css
create mode 100644 sites/all/modules/date/date_popup/themes/timeentry.css
create mode 100644 sites/all/modules/date/date_repeat/date_repeat.info
create mode 100644 sites/all/modules/date/date_repeat/date_repeat.install
create mode 100644 sites/all/modules/date/date_repeat/date_repeat.module
create mode 100644 sites/all/modules/date/date_repeat/date_repeat_calc.inc
create mode 100644 sites/all/modules/date/date_repeat/date_repeat_form.inc
create mode 100644 sites/all/modules/date/date_timezone/date_timezone.info
create mode 100644 sites/all/modules/date/date_timezone/date_timezone.install
create mode 100644 sites/all/modules/date/date_timezone/date_timezone.js
create mode 100644 sites/all/modules/date/date_timezone/date_timezone.module
create mode 100644 sites/all/modules/date/date_tools/date_field.php
create mode 100644 sites/all/modules/date/date_tools/date_tools.change_type.inc
create mode 100644 sites/all/modules/date/date_tools/date_tools.event.inc
create mode 100644 sites/all/modules/date/date_tools/date_tools.info
create mode 100644 sites/all/modules/date/date_tools/date_tools.module
create mode 100644 sites/all/modules/date/date_tools/date_tools.wizard.inc
create mode 100644 sites/all/modules/date/help/date-api-functions.html
create mode 100644 sites/all/modules/date/help/date-api.html
create mode 100644 sites/all/modules/date/help/date-argument.html
create mode 100644 sites/all/modules/date/help/date-copy.html
create mode 100644 sites/all/modules/date/help/date-create.html
create mode 100644 sites/all/modules/date/help/date-display.html
create mode 100644 sites/all/modules/date/help/date-filter.html
create mode 100644 sites/all/modules/date/help/date-php4.html
create mode 100644 sites/all/modules/date/help/date-repeat-form.html
create mode 100644 sites/all/modules/date/help/date-timezones.html
create mode 100644 sites/all/modules/date/help/date-types.html
create mode 100644 sites/all/modules/date/help/date-views-dates.html
create mode 100644 sites/all/modules/date/help/date-views.html
create mode 100644 sites/all/modules/date/help/date.html
create mode 100644 sites/all/modules/date/help/date_api.help.ini
create mode 100644 sites/all/modules/date/help/embedding.html
create mode 100644 sites/all/modules/date/help/form-elements.html
create mode 100644 sites/all/modules/date/help/new-features.html
create mode 100644 sites/all/modules/date/help/overview.html
create mode 100644 sites/all/modules/date/images/calendar.png
create mode 100644 sites/all/modules/date/images/ical16x16.gif
create mode 100644 sites/all/modules/date/includes/date_api.views.inc
create mode 100644 sites/all/modules/date/includes/date_api.views_default.inc
create mode 100644 sites/all/modules/date/includes/date_api_argument_handler.inc
create mode 100644 sites/all/modules/date/includes/date_api_fields.inc
create mode 100644 sites/all/modules/date/includes/date_api_filter_handler.inc
create mode 100644 sites/all/modules/date/includes/date_navigation_plugin_style.inc
create mode 100644 sites/all/modules/date/includes/date_plugin_display_attachment.inc
create mode 100644 sites/all/modules/date/tests/README.txt
create mode 100644 sites/all/modules/date/tests/USHolidays.ics
create mode 100644 sites/all/modules/date/tests/Yahoo.csv
create mode 100644 sites/all/modules/date/tests/date.test
create mode 100644 sites/all/modules/date/tests/date_api.test
create mode 100644 sites/all/modules/date/tests/date_repeat.test
create mode 100644 sites/all/modules/date/tests/rrule.ics
create mode 100644 sites/all/modules/date/theme/date-navigation.tpl.php
create mode 100644 sites/all/modules/date/theme/date-valarm.tpl.php
create mode 100644 sites/all/modules/date/theme/date-vcalendar.tpl.php
create mode 100644 sites/all/modules/date/theme/date-vevent.tpl.php
create mode 100644 sites/all/modules/date/theme/date-views-filter-form.tpl.php
create mode 100644 sites/all/modules/date/theme/theme.inc
diff --git a/sites/all/modules/date/CHANGELOG.txt b/sites/all/modules/date/CHANGELOG.txt
new file mode 100644
index 0000000..7173cc7
--- /dev/null
+++ b/sites/all/modules/date/CHANGELOG.txt
@@ -0,0 +1,795 @@
+Date Module 6.x
+=================
+
+Version 6.2.x-dev
+=============
+
+- Issue #1289270 by pdrake: Fixed date arguments and filters do not work with relationships.
+- Issue #973924 by arlinsandbulte: Fixed jquery_ui() dependency not in .info file.
+- Issue #895760 by Reinette: Added RFC2447 option 'STATUS' to date_api_ical().inc.
+- Issue #1192020 by tim.plunkett: Fixed Date granularity is too fragile in date_field_all_day().
+- Issue #501416 by refman1073: Fixed Date validation incorrect for days > 31.
+
+Version 6.2.9
+=============
+
+- Issue #1005968 by jcmarco, dnotes: Added Ajax for date navigation attachment views.
+- Issue #1545254, Use remember in filter only if a value exists.
+- Add a test for force_value to the code that checks the default value for the exposed filter. In some cases the relative value wasn't overriding a fixed value as it should have been doing.
+- Issue #1223956 by mikeytown2 and hyrcan, Fix undefined index in date_handler_fields().
+- Issue #1517548 by joachim, Fix incorrect documentation for date_default_timezone_name().
+- Issue #884310 by AlexisWilke, Postgres earlier than 8.3 needs different syntax in date update.
+- Issue #606658 by johnmunro and KarenS, Make sure ical import processes multi-day all-day events correctly.
+- Issue #1282538 by benjifisher, crifi, and KarenS, Make sure ical feed for all day events adds 1 day to the end date to comply with the spec.
+- Issue #1463438 by hyrcan, Fix some 5.3 notices.
+- Issue #1513396 by JoeMcGuire, Fix failing Date Popup test.
+- Clean up to eliminate PHP notices when running tests on PHP 5.3.
+- Issue #1408216 follow up, Need to be sure that NULL is the default state for the sql functions.
+- Issue #337666, Make sure the UNTIL date for repeating dates is inclusive.
+- Backport the D7 version of date_ical.ical.inc to D6 so we can keep D6 and D7 synched up more easily.
+- Issue #975320 by mvc, Add translation to jQuery date picker.
+- Issue #1408216, Remove remaining references to ->offset, which is no longer defined, nor needed. The timezone defaults should be properly set by date_views_set_timezone().
+- Issue #1408216 by technicalknockout, artkon, tangent: Fixed Events no longer appearing in calendar (regression introduced in Issue #1017866).
+- Issue #1360672, Fix limit format code to remove leftover non-ascii text as well as leftover ascii text.
+- Issue #1033856 by joachim: Fixed conflicting messages about jquery UI requirement.
+- Issue #1049992 by jjwhitney: Fixed Failed validation causes values to disappear when using popup widget.
+- Issue #436490 by kong, xjm: Fixed Add support for jQuery update to 1.3.x and jQuery UI 1.7.x.
+- Issue #1161814 by Scyther: Bad code in function date_field().
+- Issue #232954 by rho_, arlinsandbulte: Fixed text 'Empty 'To date' values will use the 'From date' values' is always visibl under the second row of selectboxes ('date - to').
+- Issue #536832 by aturetta: Fixed Date format types not translated in admin pages.
+- Issue #488078 by emmajane: Fixed Broken link.
+- Issue #1017216 by tim.plunkett, arlinsandbulte: Added custom date format without time shows 'all day'.
+- Issue #1407064 by nairb: Fixed undefined function drupal_substr_replace().
+- Issue #1162962 by mikeryan: Fixed E_STRICT notices in date_make_date().
+- Issue #554546 by master-of-magic: Fix Timezone list translation
+- Finally found why tests are failing on d.o. Some of the needed modules aren't getting set up in the test.
+
+Version 6.2.8
+=============
+
+- Make sure the value passed to set the starting nid for converting events is an integer.
+- Explicitly turn 'date_popup_timepicker' to 'none' in tests to avoid Date Popup test failures.
+- Issue #1300274, Backport all the fixes for date_repeat_build_dates() from D7 so additions will work right in PHP 5.3.
+- Issue #1130814, Backport all the fixes for Date Repeat Calc from D7 so PHP 5.3 will work right and tests will pass.
+- Issue #1391374 & #1302052 by benjifisher, CRLF line endings cause problems with git apply
+- Issue #1101284 by pfournier, Expand regex for Month names to catch more possible variations.
+- Issue #1086100 by ayalon, Group Multiple Value functionality is broken
+- Issue #752550 by Fonant, Week number gets printed twice
+- Issue #1038482 by somanyfish, iCal import failing due to colon instead of semi-colon
+- Issue #1052586 by jpsolero, Problem with Date API when using Calendar with argument set to "Week" granularity and "current date" default argument
+- Issue #307274 by ksenzee and arlinsandbulte: Limit the selectable date range using absolute values instead of only the relative Years back and forward:
+- Issue #742146, Add option to remove X-WR-CALNAME if VEVENT is not a feed.
+- Add option to change method from PUBLISH to REQUEST in VCALENDAR.
+- Issue #1087798 by anj, Fix X-WR-CALNAME in VCALENDAR.
+- Issue #1017866 by KarenS and Jason89s, Make sure views argument and filter don't do timezone adjustment for dates that don't have time.
+- Issue #1204988 by paulsheldrake, Remove IE6 code from 1.7 datepicker CSS.
+- Issue #1159404 by mikeryan, Fix incorrect call to parse an rrule in date_repeat_build_dates().
+- Issue #1160614 by joelstein, Make sure date repeat rule gets split correctly no matter which line endings were used.
+- #1018412 by omerida: get_class() called without object
+- #1054458: Move date_increment_round() function into Date API module so it is always available.
+- #745074, by rsevero: Don't test for valid timezone-adjusted date for dates that don't use time.
+- #1082658: Saving the options as arrays breaks other things. Add a custom export plugin instead.
+- #1082658, Views options need to be declared as arrays or they are not saved in the export in Views 3.
+- #945982 by tstoeckler, Fix another PHP 5.3 warning.
+- #1027752 by B-Prod and dboulet, Fix missing table join on argument summary view.
+- #686394 Fix computation of week when week is used as default value of date argument.
+- #447868 Figure out when remembered value needs to used in Date filter.
+- #430746 by Kermit, Fix missing datetime type in event migration code in Date Tools.
+- #1011184 Add function to sort granularity array and use it in date_make_date().
+- #1014664 Fix timezone shifts when computing UNTIL date for repeating dates.
+- #1014818 Fix bug that only affects old versions of php to show all dates as the current date. Those old versions cannot be made to work the same way, fall back to a less robust workaround.
+- #580176 Fix alias handling when dates from multiple content types are used in same view.
+- #1013662 by developer-x: Remove check for start and end date - this prevented multiday-all day events from showing 'All Day'
+- Add more tests.
+
+Version 6.2.7
+=============
+- #514242 Day repeated every two weeks was broken by wrong day comparison value.
+- Fix a bug in the calculation of the week days when using ISO weeks.
+- #549042 The date_week() function should return an integer even when using ISO weeks.
+- #575770 Fix handling of empty vs zero date parts in the date combo processing.
+- #385688 by jcmarco, Make sure we don't set relationships where there should be none.
+- Fix a strict warning for use of is_a().
+- #882980 Fix WSOD in PHP4 from date_format process to create a new date.
+- #998498 Don't try to use jquery_ui function in update if it isn't installed, add a warning message.
+- #993148 Use url() for link to date format page in date widget settings so it works without clean urls.
+- Add more date repeat tests and fix date repeat handling of day of month > 5.
+- #784854 by akeemw, fix broken date repeat handling of negative by-day computations.
+- Add functions to get a granularity precision from a granularity array or an array from a precision.
+- #760284 by skwashd, arithmetric clean up ical rfc compliance.
+- #939152 by amelfe add z-index to datepicker 1.7.
+- #826458 by troynt Keep date popup from popping up on page load.
+- #441970 by recrit and patcon, tweak year range validation in date filter and date argument to be more flexible.
+- #952036 by cwc, Date popup defaulted to earliest year instead of current year when using jquery ui 1.7.
+- #977002 Ensure that the year range always sets the minium year as the minimum even if the year range string has it reversed.
+- #848656 by Mark Trapp, remove use of ereg from date_calc for compatibility with PHP 5.3.
+- #385688 by christianchristensen Fix filter handling for relationships.
+- #963844 Fix the date filter and argument so they will show up both under the 'Date' group and as 'Content' fields.
+- Add tests for date popup widget.
+- #560054 by travist and AllPlayers.com, add AHAH Add More buttons to date repeat exceptions and additions.
+- #292522 by chaps2, fix typo in new date repeat additions feature.
+- #292522 by chaps2, add additive exception to repeating date form.
+- Avoid errors with incomplete time values in dates.
+- #337666 Fix UNTIL and EXCEPT dates to not show time and automatically set them to 23:59:59 before storing.
+- #769064 Fix translation in format example text.
+- #898024 by jaydub and #834388 by arroncouch Fix the jquery ui css paths.
+- Adding and updating test, including a test provided by tristanoneil, with a few fixes uncovered by the tests.
+- #521990 by Aron Novak: Make sure popup date selector grid is in correct year by.
+- #587338 by Kevin Rogers - Add token to support day number with English ordinal (st, nd, rd or th).
+
+Version 6.2.6
+=============
+
+- Revert #802046. Unicode support change for date parsing causes serious errors.
+
+Version 6.2.5
+=============
+
+NOTE: The included copy of the jQuery UI datepicker in the Date Popups module has been removed. It is now necessary to install the jQuery UI module (http://drupal.org/project/jquery_ui) for the Date Popups datepicker to work!
+
+- #436490 Add support for the jQuery UI 1.7 datepicker.
+- #802046 by t3hk0d3, fix date parsing to better handle unicode characters.
+- #475926 by hawleyal, clean html out of ical export.
+- #675352 by sdague, clean up ical escape text.
+- #848644 by Crell, make sure ical_parse_rrule can handle embedded timezones.
+- #784652 by keinstein, fix 'r' format.
+- #679224 by brianV, add defaults for month and year for latest jQuery UI datepicker.
+- #518816 by dww, avoid 'date_format() expects parameter 1 to be DateTime' errors by checking for date class.
+- #772180 by recrit and dww, make sure date descriptions always use valid dates for format examples.
+- #642018 by slip and KarenS, make sure to eliminate spaces before AM/PM in date popup timepicker.
+- #582982 by yahn, make sure date_all_day gets the most significant date element.
+- #785708 by bdurbin and locomo, update jquery timeentry to latest version.
+- #390012 by joachim, Make sure view args are sorted when creating navigation links.
+- #408190 Fix mini calendar title link so it doesn't always link to current date.
+- #630972 by bec, make sure a default system timezone is set to make PHP 5.3 happy.
+- #641344 by arlinsandbulte, add option to use ISO weeks instead of calendar weeks.
+- #697144 by tstoeckler, date_format_date formatter fixes.
+- #774182 by keinstein, fix some strict error handling errors.
+- #702922 by rupl, add missing class to date popup.
+- #660776 by neilnz, fix postgresql sequence update.
+- #645936 by markus_petrux, allow other modules to add #afterbuild to user forms.
+- #406976 by dopry, Check both the field name and type name to get the right label for shared fields.
+- #599744 by anarcat, don't rename table to one that already exists.
+- #599484 by Gribnif, avoid infinite date repeat in PHP4.
+- #529734 by raintonr, reduce number of requires for PHP4.
+- #875978 by mikeryan, avoid notices when updating nodes with empty datefields.
+- #548866 by siritree, fix cannot use scalar value as array by testing that $item is an array.
+- #706006 by Gribnif, fix broken logic for every Nth DAY.
+- #460776 by Mr. Chips, fix ordinality in Date Repeat string.
+- #635778 by dagmar, fix typo keeping comment dates from showing up.
+- #819678 by jonathan1055, fix url on admin page to work without clean urls enabled.
+- #553884 by divinehawk, fix pgsql timezone support.
+- #320765 by joelstein, fix order of timezone name list.
+- #552154 by Ian Ward, make date_first_day defaults consistent.
+- #477868 Exposed select filter widget sometimes gives 'illegal choice' errors.
+- #385688 by Gribnif, adding a set_relationship() function to date filter and date argument to try to fix broken relationships problems.
+- #580178, Remove http://drupal.org/cvs?commit=263582, might be a problem.
+- Fix default values for date_fields, should be array.
+- Rename incorrectly named views definition.
+- #313704 Add timezone information earlier so that auto_nodetitle has it, patch by Kars-T.
+- #554546 Don't put translated timezone names in cache, patch by alex.k
+- #491954 Make sure translation works in date changer, patch by Bodo Maass and cyp25.
+- #675234 Try to convert deprecated timezones in ical, patch by David Goode.
+- #535270 Test for existing date format tables before update, patch by anarcat and Owen Barton.
+- #545466 Fix bid placeholder in date wizard, patch by colinsherry.
+- Be sure to set timezone when changing date type. Clean up unused parts of code from Date Wizard.
+- More work on repeating dates.
+- Adding experimental tool to change the date type.
+- Move event import and date wizard into separate files.
+- #698522 Make Views code work with Views 2 and Views 3, patch by rjbrown99, Ahqar, tauno, dagmar, perusio.
+- Coder review fixes.
+- Install file cleanup.
+- #489494, by poiu, Some RTL css fixes.
+
+Version 6.2.4
+=============
+
+- #565830, by bengtan, Fix Postgres handling of hour '0'.
+- #408770, by vkareh, Make sure dates with access control retain values during processing.
+- #574876, by stella, Fix odd logic when forcing views dates in date elements.
+- #385688, by noahb, a fix for using relationships with date filters and arguments. Thanks!
+- #535008 Prevent possible PostgreSQL problem by re-arranging timing of dropping the key.
+- #535270 Fix install test for update 6005 that kept it from completing.
+- We sometimes get $edit without $edit['date'] from Views exposed filters, fix processing for that possibility.
+- Exposed filter querystring must be appended in normal views.
+
+Version 6.2.3
+=============
+
+- #494350 Add 'c' format.
+- #352975 Remove filter:mask in datepicker css and add help in settings on how to add back in theme.
+- #352975 Add hook_requirements warning to suggest using jQuery UI for datepicker.
+- #529826 Change date tools permission name to add 'administrator' to make it clear it has important powers.
+- #529826 Check for invalid content type name in Date Tools.
+- #529826 Add check_plain to label.
+- #418874 Don't run timestamp format through date_limit_format().
+- #456308 Don't reset date_api_fields cache over and over.
+- #424006 Add flexibility to date filter options by passing them directly to date_create.
+- #465870 Make sure date_repeat_form.inc is included in validation.
+- #453688 Use is_a() function so date handler will work for any handler derived from views_handler_field_date.
+- #452934 Make sure format_interval() doesn't do anything with empty dates.
+- #483682 Make searches case-insensitive.
+- #395156 Change table name for date formats from 'date_format' to 'date_formats' because 'date_format' is reserved word in some dbs.
+- #342357 Make jQuery timepicker optional.
+- #473308 Add handling for year-only date stored in timestamp field.
+- Get rid of in admin summary that was going through check_plain.
+- #482436 Removed deprecated code to remove empty field values, CCK does that now.
+- #421258 Don't cache prepared node, it may need to change context or content type.
+- #421258 Make sure formatter settings context is never empty.
+- Add theme date_time_ago() to Date API so other modules can use it.
+- Remove deprecated date_format_options().
+- Remove deprecated Views code.
+- Remove deprecated date_install_clear() function.
+
+Version 6.2.2
+=============
+
+- #418174 Timestamp format should not be run through date_limit_format().
+- #456308 We do not have to reset the date_api_fields cache over and over!
+- #424006 Add flexibility to date filter options by passing them directly to date_create() for PHP versions > 5.2.
+- #465870 Make sure date_repeat_form.inc is included in validation.
+- #453688 The is_a() function makes date handler api work for any handler that was derived from 'views_handler_field_date'.
+- #452934 Make sure format_interval doesn't try to do anything with empty dates.
+- #483682 and #395156 Have to alter the collation of the format fields in MYSQL so they don't do case-insensitive searches and indexes. Fixing table name at the same time to fix another sporatic problem where 'date_format' is treated as an invalid table name and the table is not created.
+- #342357 Make jQuery Timepicker optional.
+- #466222 Fix Dutch translations.
+- #473308 Add handling for year-only date stored in timestamp field.
+- #482436 Remove deprecated code to remove empty field values, CCK does that now.
+- #421258 Don't cache prepared node, it may need to change by context and/or content type.
+- #421258 Make sure formatter settings context is never empty.
+- Add new calendar-day theme to format date like a calendar day page, move basic theme date_time_ago() from Date module to Date API so other modules can use it.
+- Remove date_format_options() from Date API, no longer used with new format system. Move it to Date Popup, which is the only module still using it with TODO to maybe get rid of it.
+- Remove old views code from Date module.
+- Remove date_install_clear() function, a leftover from an earlier version no longer needed.
+- #451858 Fix date_timezone_set() when date is empty while adding new item.
+- Fix date_limit_format() to be sure the 'T' is stripped out of ISO dates with only date or only time.
+- #432368 Don't force default value in exposed filter if default is empty.
+- #369020 Switch '+1 Sunday' to 'First Sunday' to over PHP5 bug.
+- #444960 Fix Date Tools permissions.
+- #315443 Make sure 'within' labels don't break when used in text fields.
+- #423710 Make date navigation more accessible with titles.
+- #424388 Pass #attributes from element to Date Popup.
+- #381370 Remove escaping for colon and double quote per ical spec.
+- #426810 Fix HTML syntax in advanced help files.
+- #456460 Break out simple themes for date_display_single and date_display_double for easier control by themers of separator and other html.
+- #384258 Fix broken handling of 24 hour time in Date Popup.
+- #401152 Fix broken handling of long month name in input format.
+- #452420 Revert change of hyphen to dash in date display, dash is handled badly by token and elsewhere.
+- #347080 Using 'first' and 'last' is more reliable than '+1 week' in strtotime().
+- #369020 Fix bug when finding first or last Mon/Tue/Wed/Thu/Fri/Sat/Sun of month.
+- #427830 Postgres can't handle \T.
+- #414446 Avoid php errors when context is missing.
+- #444272 by Darren Oh, add Date views conversion from Views 1 to Views 2.
+- #428828 Make sure date $fields array always has expected format, even when empty.
+- #341463 Repeating date with no To date was missing form label.
+- #404866 Make sure labels are translated.
+- #442526 Add missing space to navigation template.
+- #375864 Clean up date_limit_format() to handle more odd formats.
+- #447616 Allow custom tables as well as custom fields to use Date argument and filter.
+- #338253 Fixes to translation of timezone names.
+- #409476 Make sure empty UNTIL date is not parsed into RRULE.
+- Make sure $base is never empty when identifying date fields for date filter and argument.
+- #317105 Update Isreal DST rules.
+- #408770 Abort date_combo processing when user has no #access.
+- #388728 Change dash to en dash in date range theme.
+- #414290 Update timezone form_alter to account for difference between Event version 1 and 2.
+- Broke un-exposed filters when fixing exposed filters, fixing them again.
+- Non-node date fields need better descriptions and field limits.
+
+Version 6.2.1
+=============
+- #411496 Select widget in Views was not getting forced to the right value when using 'now+' defaults.
+- #395156 Hide errors during multiple passes of date_format creation.
+- #395156 Update new format table definitions to be sure indexes are not too long for MYSQL to create the tables.
+- #365771 Make sure date filter doesn't try to use Date popup widget if that module is disabled.
+= #406876 Adapt Views block argument handling to adapt to arguments like user/%/calendar/2009-05.
+- #385880 Add non-node date handling for Views arguments and filters.
+- #400992 Add time and datetime tokens.
+- #408176 Fix token handling of empty values.
+- #399180 Test for Views tables before uninstalling them.
+- #369811 Fix problems with duplicate date formats in new format system.
+- #354989 Make sure year-only date does not regress to YYYY-00-00 00:00:00, which will end up as previous year.
+- #398258 Fix problems handling blank text widget values and general form processing cleanup.
+- #405408 Update simpletests.
+- #397420 Fix miscalculation errors in date_difference.
+- #360967 Add method for deleting a custom default calendar.
+- #376224 Add 'From date' and 'To date' to Views titles.
+- #375864 Make sure date_limit_format() doesn't keep formats that are only escaped strings.
+- #386124 Updates that test for Views version should work even if Views is not installed.
+- #386406 Date filter was not picking up right default value in some situations.
+
+Version 6.2.0
+=============
+- #376880 Move back/next symbols back into link.
+- Exposed filter was not testing empty values correctly.
+- Add Advanced help for new formatter settings.
+- Add formatter settings for node and view to control which multiple value to display when.
+- Improve interpretation of argument date ranges.
+- Improve handling of translation for Date repeat rules.
+- #347645 Mark 'To date' required if it is.
+- #345215, #309921 Rework the way multiple 'From date' and 'To date' fields are identified in validation errors.
+- #375551 The 'All day' formatting should not be applied to format_interval formats.
+- Date PHP4: fix inconsistency in offset computation for first two hours of the day dst changes.
+- Date PHP4: eliminate some needless cycles to improve performance.
+- Add test files to import RRULEs in .ics, all day dates in .ics, and date info in .csv formats used by Yahoo Calendar and Outlook.
+- iCal TRIGGER can either be a date or a duration.
+- Fix to iCal: alter the end date of all day events to match the to date.
+ The ical practice of setting the End date as the next day won't work for our interal use of this value.
+- Fix to iCal: leave 'all day' notice in the individual date components as well
+ as the top level so it is available in each portion of the VEVENT array, needed for FeedAPI parsing.
+- Fix broken date link in calendar created by Date Tools.
+- Make the default value for the 'To date' easier to see in the field settings.
+- Update date argument summary for recent changes in Views.
+- #345077 Make sure duplicate copies of the date field each get to theme the raw, unaltered, data.
+- #375551 Fix fatal typo in reworked date_format_date() function.
+- #338253 Re-work the Date repeat description to provide more context for translations.
+- #338253 Re-work date_t() to create a more robust method of handling translations of abbreviations and other short strings.
+- The date filter should not be setting the view dates, the style should do that.
+- Add 'value' and 'value2' hints to views fields and use new CCK views data.
+- Give the Date browser a better path with no underscore.
+- #370961 Date format update was not PostgreSQL-safe.
+- #337301 Move hook_schema_alter from date_api.module to date_api.install.
+- #367688 Fix date format css to display remove link better.
+- Add our custom date formats as values on the core locale form so we don't get errors on submission if they are missing.
+- #348241 Don't unset view copy on node because it interferes with template suggestions. Need to watch this for possible performance problems.
+- #364770 Add new date link needs to convert underscore to hyphen.
+- Can't use date-clear attribute on timezone list.
+- #370092 Add all-day checkbox to date field and use it in calendar.
+- #347090 Fix southern hemisphere timezone adjustment for PHP4.
+- Make sure un-exposed filter checks for defaults to find values like 'now'.
+- Fix bug that caused date_select to end up as current date.
+- #364919 Fix typo in html link for date format information.
+- #360670 Rework date_range to better handle absolute as well as relative years in argument and filter.
+- #367970 Fix date filter bugs, better handling for partial dates and force date popup to use the right default value.
+- #313369 Repeating date with exceptions created error when exceptions data is appended.
+- #363424 Empty value should be object, not array.
+- Fix bad PHP4 regex that caused endless looping in calendar and broken logic elsewhere.
+- by stella, nedjo, grugnog2, and catch: #318008 Create new system for handling flexible date formats that can be adapted by locale.
+- Make sure prev/next links point to the right path when another argument precedes the date argument and is empty.
+- Don't try to set date argument when another argument precedes it.
+- Make sure theme functions can be discovered even when called from unexpected places, like embedded views.
+- Make the PHP4 code forgiving enough to accept '+ 1 month' instead of '+1 month'.
+- Overcome Views form handling to make sure text and Date popup exposed filters will default to the right values.
+- #348276 Remove class date-clear-block from timezone element.
+- #217153 Remove asterisks from custom format now that they are explained in advanced help.
+- #292942 Only load timezone js file in timezone forms.
+- #313427 Don't add the date field to the view, it may be enough to join the table in.
+- #356564 Add Date popup option for exposed date filters.
+- #349306 Incorporate year range into date filter year option.
+- #312403 Add NULL/NOT NULL handling to date filter.
+- #356305 Date filters needed a rewrite to properly handle between with more than one date field.
+- #350656 Fix broken handling for 'time ago'.
+- #307578 Add permissions for viewing date repeats tab.
+- Clean out unused part of Date Popup jQuery code for easier maintenance.
+- #347080 Fix PHP4 southern timezone computation and New Zealand region.
+- #353327 Check for Event 2 timezone table before trying to use it.
+- #310633 Rework 'all day' logic to correctly handle increments.
+- #345953 Fix report of update failure from missing content_check_update() function.
+- #348157 Beautiful new datepicker popup themes and images from hass. Thanks!
+- #357226 Don't translate menu items.
+- #357094 Remove extra parenthesis.
+- #346752 Add RTL css code.
+- #324290 Don't validate when $items is empty.
+- #348375 Add missing php tags in template.
+- #347878 Translation fixes.
+- Add new module 'Date tools' with date wizard to easily create a simple date content type with an auto-configured related calendar.
+- #313704 Make sure date db timezone does not get removed before token handling.
+- #313704 Fix token 'From date' value that was using 'To date' value.
+- #327897 Fix To-view token in date_token.inc
+- #345862 Fix missing close comment tag in datepicker css.
+- Date input and display formats were not properly defaulting to the site default values.
+- Improve the template and css for the exposed date filter to keep date parts lined up next to each other.
+- Fix handling for fixed date default value in date filter.
+- Get rid of DURATION time part details in iCal array, we only need the DATA and DURATION.
+- #282521 Do more work on LOCATION to split out UID and handle odd upcoming.org location identifiers.
+- Add more error trapping to ical parser.
+- Add handling to ical parser for odd upcoming.org location format.
+- #341705 Fix broken iCal DURATION parsing.
+- Add some protection against empty or missing info in ical parser.
+- #343126 Fix date argument handler type assignment.
+- #343190 Add validity testing to date_api_ical_build_rrule().
+- #307166 Make sure timestamps with missing granularity parts in select widgets get defaulted to empty values and saved correctly.
+- #341203 Make sure there is no SQL error if there are no fields.
+- Add ability to analyze a period to period argument, like P1M--P1Y.
+- Adapt Date Argument/Date Browser code to work correctly if only a period is used.
+- #324063 Remove unneeded break.
+- #320596 Add hook to date_api_fields() so custom modules can add date fields to the Date argument and filter.
+- #341964 Get missing back/next links back in year.
+- Add date_increment_round() to date_content_generate to make sure generated dates match increment settings.
+- Move Date repeat form help to Advanced Help instead of using collapsed fieldset.
+
+Version 6.2-rc6
+=================
+
+- #341202, #339457, #337952, #329128, #337787, #341203, Fix repeating and multiple date displays.
+- #273093 Add time formatter option to use in calendar views.
+- #324063 Unset invalid values in the date argument position of the url to avoid various errors in the date argument handling.
+- #301279 Remove README.txt for Date Popup, it's out of date and I'm moving documentation into the d.o handbook and Advanced Help.
+- #337075 Change background-color:none to background-color:transparent.
+- #324756 Bypass validation for empty, non-required dates.
+- Fix broken Date API test broken by change in API.
+- #340394 Fix four-digit year format for PostgreSQL.
+- Fix bug in new date_field_get_sql_handler() helper function to pick up the right timezones for the handler.
+- #338277 Make some improvements to datepicker css.
+- #326722 Update the datepicker js to the latest version to fix bugs in current version.
+- Date picker can't handle some year ranges that work in Date API, so adjust it as needed.
+- #324150 Fix broken 'not between' date filter handling.
+- #337784 Fix broken date filter to work correctly with the new year range values.
+- #338237 Replace 'local_offset_field' with 'offset_field' in date handler.
+- #338237 Fix broken date browser which never got updated to move date field info to $view->date_info.
+- Make sure node edit form uses the right timezone for the database and field type.
+- Fix logic error in date_convert when using timestamp with timezone other than UTC.
+- #336255 Fix a few remaining places where timezone=none was not being handled correctly, and add update to clean up incorrect values stored in database.
+- Eliminate date_timezone_convert() which wasn't working correctly to adjust dates without timezones and get rid of hard-coded 'UTC' for database values in favor of consistently using date_get_timezone_db().
+- Date sql handler wasn't properly setting db timezone to UTC for mysql databases.
+- Add a helper function date_field_default_values() that can be used to create new date fields in profiles and custom code.
+- Add better separation to multiple date fields in the view admin summaries for date arguments and filters.
+- #337764 Date filter wasn't correctly setting view date info, and also needs a year limit.
+- #337301 Add hook_schema_alter to record addition of timezone_name to users table.
+- #336255 Add new helper functions to make work of other modules, like Signup, easier. One helper to create a date handler for a field and another to do make date math easier.
+
+Version 6.2-rc5
+=================
+
+- #309155 Get rid of all translation during date_repeat calculations, it was causing timeouts with locale module.
+- Rename values added to views to avoid name clashes and keep all date values together.
+- #336109 Add handling for ordinals to custom date formatting.
+- #265076, #324794 Revert attempt to use strtotime to 'guess' text input since it too often ends up silently turning into 'now'.
+- #303951 Relax requirements for text date input to allow single digit months and days.
+- #309617 Make DATE_REGEX_LOOSE a bit looser so the @ argument will work right for single digit months and days.
+- #333831 Make sure Date Repeat widgets are not made available if the Date Repeat module is disabled, and add hooks to mark repeating widgets active and inactive when the module is enabled and disabled.
+- #332806 Make sure that Date Popup widgets are marked active when the module is enabled.
+- Adapt processing to make sure only selected dates display in nodes, views, and calendars.
+- Add Views field handler for date that can be smarter about grouping date values in views.
+- Do a little more work on clarifying the repeat descriptions.
+- Fix PHP4 timezone problem that didn't save timezone changes correctly in rare cases when refreshing zones using devel.
+- Add 'UNTIL' to the RRULE creation function so it can be used by the API and date_content_generate.
+- Update date_content_generate to find more matches in a more limited period.
+- Make sure repeating date UNTIL date is properly adjusted for timezone.
+- #296529 Update repeating date computations to properly adjust the UNTIL date to the right time and timezone so the end date gets picked up correctly.
+- #319452 Fix bug in PHP4 calculation of +/-1 week when using Monday as the first day of the week.
+- #319452 Make sure repeating date calculations like 'the 5th Sunday' don't prematurely jump to the following period.
+- Fix bug in PHP4 calculation of date_date_set() that was getting the day wrong.
+- Another tweak to the repeating date theme to show only the first date in nodes, but show the current date in views.
+- #329102 Fix mistake in README.txt.
+- Set up hook_content_generate to creating random repeating dates as well as regular dates, useful to help debug repeat problems.
+- #322845 Repeating dates with deltas greater than zero were showing no date in Views.
+- #315009 Rework the generation of dates to work right now that the Content module handles repeats.
+- #317057 Make sure existing optional date with empty value doesn't get reset to current date.
+- Fix incorrect handling of empty values for multiple value fields, make sure they remain empty.
+- Add more checks in PHP4 functions to return usable values when we don't have complete timezone information in the PHP4 wrapper.
+- Add helper function to convert input values based on field type.
+- Fix timezone caching -- it was resetting when it didn't need to, consuming resources.
+- Found a better way to generate random timezones using mt_rand() instead of rand() to avoid getting lots of duplicates.
+- Found some timezones that can't be used in PHP4 because we don't have offset information, so remove them from timezone lists.
+- Fix error in PHP4 dst switch date for North America.
+- Clean up admin summary names for the date argument and date filter.
+- #327506 Detect and trap bad timezones in ical import so they don't create errors.
+- Fix broken SQL for week arguments and filters, we can't use DATE_FORMAT(), must look for week start and end.
+- Default the block_identifier to NULL, not 'mini'.
+- Make sure the date filter as well as the date argument can use both the OR and AND methods of combining dates.
+- Fix undefined index error for 'step' in date_copy.
+- Remove ical import from Date Copy and add instructions on how to do it using Feed API to Advanced help.
+- Add a date_embed_view() function to provide a way to embed views and have their navigation move either together or separately, and document it in Advanced help.
+- #326945 Remove callbacks in date_field hook() to match CCK.
+- Get the links in embedded views and blocks to work correctly using a helper function date_real_url().
+- Fix undefined variable in date_ical.inc.
+- Set view->date fields when using date filters as well as date arguments.
+- Fix Date Views argument handling of summary views, and switch to comparing formatted values instead of complete dates so year arguments will work better.
+- Make sure 'time ago' formats will work in calendar by adding more separation into the format_interval formatter.
+- #240156 Workaround conflict between Event and Date by using #process on timezone forms to override Event module handling.
+- Keep year out of mini navigation title, and make sure it is a link to the view.
+- #323265 Add year as well as month to Date browser & calendar titles.
+- #174580 Add min/max year setting to Date argument and set Page Not Found outside that range.
+- #174580 Add rel=nofollow to back/next links.
+- #322649 Add escaping for %s in date format code.
+- #322446 Avoid extra space in date theme when there is no timezone.
+- #321733 Fix identification of error field for To date that is not greater than From date.
+- Fix Views date filter summary, which was using wrong index.
+
+Version 6.2-rc4
+=================
+
+- Date argument handler: Add date field in pre_query() instead of query() so it works if the argument is set to the wildcard.
+- Don't try to trim date objects in the date ical preprocessor.
+- Make a few more fixes to CCK updates in date.install.
+- Start on Advanced help for the Date module.
+- #317660 Hard code line feeds in ical export to be sure they come through correctly in all systems.
+- Don't try to find repeating fields on types without fields.
+- #317021 Coder module patch by stella.
+- #312996 Break out of endless loop in date_repeat calculation.
+- #294851 Date PHP4: Make timezone_identifiers and timezone_abbreviations into statics variable to reduce execution time.
+- #294851 Date PHP4: Make timezone_map into a static variable to reduce execution time.
+- #314959 Keep repeating dates off the teaser as well as the node.
+- #312598 Date PHP4 functions can be off by 1 hour during the day dst changes, add a fix for that.
+- Date PHP4: Add new settings area where you can choose whether to use the faster native timezone adjustments for current dates.
+- #316392 Hard code the date_api_views_clear() code to prevent update errors.
+- #315955 Translation cleanup.
+- Add new repeat selection widgets to widgets that can set increments and date parts.
+- #304813 Use new recommended method of testing CCK updates using content_check_update().
+- #307544 Get rid of extra line feed at end of ical description.
+- #304370 Fix typo in popup css.
+- #265076 Add some fallback handling for text input that can accept missing time.
+- #308353 Long month name translations again, I applied the fix to the wrong function.
+- #313447 Throw an error on required dates that have no values filled out.
+- #312539 Improvements in translation text.
+- #296529 Remove text saying UNTIL date is not included in results, it should be.
+- #296529 Make sure UNTIL date takes time into account to avoid missing final date.
+- #312974 Add missing closing span in date theme.
+- Clean out date displays in Views tables when uninstalled.
+- Fix undefined indexes in Date repeat widget logic.
+- Add in special widgets for repeating dates so normal widgets can use the regular Content module multiple values handling.
+- #309196, #310728 Get rid of attempt to simplify the navigation query, it is too easily broken.
+
+Version 6.2-rc3
+=================
+
+- #305376, #303999 Change method of clearing theme registry to avoid errors other themes during update.php.
+- #308353 Use long-month-name protocol for translations.
+- Eliminate query for navigation display.
+- #306404 Make sure update 6001 returns an array.
+- Default Date Browser view should not have a content type filter in it.
+- Add some validation to date repeat logic to avoid trying to process invalid values.
+- #303999 Add function and update to clear out theme registry and all the views caches to pick up changes in Views definitions.
+- #304631 Fix validation check for required field that was always triggered.
+- #304762 Add missing folders for translations.
+- #198502 Make sure updates abort if Content module hasn't yet been updated.
+- Update to new Views2 API. Now requires latest versions of Views and CCK, and files have been re-arranged.
+- Move timezone handling logic to Date API so we can use it in Calendar, too.
+- Rework the date_id formatting to use the new #delta value being passed from CCK.
+- #196468 Add link to add a date field to a content type in Date Copy, uses new CCK feature to import from file.
+- The timezone translation names in the install file must use underscores instead of spaces.
+- #302351 Add timezone info to node_load() and adjust tokens to set the right timezone.
+- Replace all include_once() with require_once().
+- #276270 Add missing break in date_convert() switch for ICAL.
+- #301385 Change hook_requirements() to only set message in runtime to avoid install profile errors.
+- #299112 Adjust date_convert() to adapt to am/pm when data source is an array.
+- #299112 Don't change 12 hour time to 24 hour time until after validation.
+- Make sure date_week() trims input value so you can use it with a regular datetime value.
+- Change error messages for ical imports to watchdog messages.
+- #294185 Add function for cross-database test of non_null values using COALESCE.
+- #300319 Move apostrophe in PostgreSQL offset code.
+- #299594 Alter date_api_sql to handle MYSQL versions prior to 4.1.1.
+- #297733 Make more kinds of custom formats display correctly.
+- Change date description for empty 'to' dates to only be used on date_select, the only place it will work.
+- Clean up Date Popup validation.
+- #275919, #267195 Clean up date_select validation:
+ add field name to from and to date so the name can be used in error messages,
+ combine error messages for field parts into a single message,
+ remove #options from text elements so we don't get meaningless core message about an invalid option,
+ set error on whole element so error fields will get outlined.
+- Fix weights for timezone and repeat form to always keep them below the date.
+- #290212 To date with 'same' default value wasn't picking up blank value when needed.
+- #290652 Update jQuery datepicker to development version to pick up fix for duplicated dates when dst changes.
+- #298456 Add warnings to field settings page about changes that could result in loss of data.
+- #295095 Fix access control on repeating dates tab so it only shows on repeat nodes.
+- #295860 Fix flawed updates that were not resetting jscalendar widgets correctly.
+- #298158 Change drupal_get_path() to drupal_load() to be sure content module gets included correctly in install file.
+- #296409 Fix the hidden repeat date logic so repeating dates are only hidden on the node.
+
+Version 6.2-rc2
+=================
+
+- #292617 Make sure the Date Repeat form works properly with all possible date widgets.
+- #273656 Make the Date Repeat form use the same widget the regular date form uses.
+- #240156 Update Event module timezone values if the Date module is handling the timezone form.
+- #296051 Fix error in computation of last day of calendar month.
+- Clean up some invalid combinations like using 'DAILY' with an option like 'First Tuesday'.
+- #284557 Fix errors saving repeating date when no repeat options were selected.
+- #295095 Change the repeating dates theme to show only the start and rule on the node and move the list of repeating dates to a separate tab.
+
+Version 6.2-rc1
+=================
+
+- Fix Date Popup process that was ignoring $edit values.
+- #289215 Shorten the size of Date Popup date box and allow the API to control the size.
+- #291882 Do some tweaking of the Date Popup css to be sure backgrounds are hidden and values are overridden.
+- #292945 See if there is an existing validation array before adding validation.
+- #293685 Add missing $form_state in form_set_value() call in date_repeat.inc.
+- Fix broken logic in comparison of min and max to from and to dates in the date argument.
+- #272551 Remove weight for repeat element, it isn't needed and doesn't work right when weight is negative.
+- #283392 Make sure widget description shows up with or without 'to' date.
+- #292680 Make sure themes don't add padding to navigation h3 causing misalignment.
+- #292602 Make sure dates without times do not get 'All day' added.
+- #292436 Fix critical typo in new date_all_day function and add test to date_formatter_process() to keep empty value from wiping out a good one.
+- Check for date values before using new all day theme.
+- Add 'All day' themes for use in nodes and calendar psuedo nodes.
+- #290826 Fix logic error that was missing date ranges that start before the current period by changing 'AND' to 'OR' in argument filter.
+
+Version 6.2-beta4
+=================
+
+- #270318 Get date browser and calendar navigation working correctly when used in a block.
+- Add new DATE_FORMAT_DATE for date-only format that is used throughout the calendar.
+- Fix validation code that checks if arguments and filters have date fields selected, need to array_filter() the selections.
+- #269569 Override Views default method of combining tables when adding two fields from the same table, needed to avoid broken queries.
+- Add validation for Date Browser to be sure only one date argument is used in the view.
+- Rework the install file so variables can be corrected and dependent modules enabled by disabling and re-enabling Date API.
+- #280863 Make sure Date Timezone and Date PHP4 can be uninstalled by keeping module_enable() in the install.
+- Rework of date filter to provide a choice of a widget to use for the filter form and an option to set the default value to a set date or something like 'now +90 days'. You must delete any previously-created date filters and re-create them to pick up the new parameters.
+- Make sure PHP4 date_modify() does not care if there is a space between the number and the date part.
+- Make sure we don't use mktime() in compare_date() function, won't work reliably in PHP4.
+- Make sure PHP4 wrapper code doesn't try to use date() on values outside the 32 bit signed range.
+- Get the url into the theme processing.
+- Remove old D5 themes, this is now handled by the Date API date browser attachment.
+- #286864 Fix wrong RRULE value being passed to validator and add trim() to get repeating dates working again.
+- #286864 Need a different fix for timezone API since this fix broke Date Repeat.
+- #283107 Evaluate date and time parts separately since we can't know or care how they're combined in the complete date format.
+- #283107 Date Popup timepicker formats need adjustment before using date_convert_from_custom().
+- Exception dates were getting lost when parsing the RRULE.
+- Increase size of Date Popup input box to accept longer formats that the new datepicker allows.
+- #287325 Change the default date type in the date handler to DATE_DATETIME.
+- Add test for jQueryUI and load datepicker from there if it exists.
+- Update to latest versions of jQuery datepicker and timeentry.
+- Hide image div in Date Popup timeentry css to keep FF from displaying a 'helpful' dropdown.
+- Move date_format_options() to Date API so other code can use it.
+- #279247 Make sure date_timezone element works no matter what the parent element name is.
+- Fix undefined index in PHP4 date_datetime2timestamp() function.
+- #265076 Avoid use of strtotime and use date_create instead as date_text validator.
+- #277771 Fix date_gmmktime() computation in PHP4 date handling to avoid erratic daylight savings time problem.
+- Fix computation of 'now' in PHP4 date_create() function.
+- Fix some inconsistencies in the expectation of whether date_fuzzy_datetime returns a datetime or ISO value.
+- Don't use date_make_date() in date_convert() to avoid cyclical references.
+- Set a warning message for invalid non-required Date popup values instead of silently setting to NULL.
+- #244025 Fix jquery calendar so it works correctly with multiple value fields.
+- #269569 Make sure more than one date filter will work on the same view.
+- Add a template for the Date Views filter form.
+- Check for invalid inputs to the date handler argument handling.
+- Move the class configuration to the theme so it is easier for themers.
+- Remove code previously commented out that forced required value to current date, seems to be working right.
+- Adapt date elements so they will work correctly as Views 2 widgets.
+- Move #validate parameters to element processing step instead of hook_element() to help ensure they don't get wiped out.
+- Make sure partial dates, like year-only, get the right range computed for them.
+- Don't user format_date() and strtotime() to create argument titles and links.
+- #282408 Make sure dates only float when there are two of them by adding #date_float parameter.
+- #281623 Switch old jscalendar widgets to use date_text instead of date_popup since date_popup may not be available.
+- Make sure empty time does not get value on submit.
+- Format interval theme added 'ago' twice to past events.
+- Need a space between the date and the timezone name in the Date theme.
+- Get repeating dates working.
+- #280899, #273344 Make sure Date Popup doesn't inject the current date into empty fields.
+- Fix undefined index for timezone field.
+- Fix computation of year range in date_content_generate.
+- #275797 Remove invalid and unneeded css display:relative.
+- Fix inconsistencies in handling of 'none' and 'user' timezones in Date and Calendar.
+- Add static variable to PHP4 timezone offset handling to reduce number of database queries.
+- #280041 Fix typo in postgres switch code in date_api_sql.inc.
+- #264749 Fix typo in date_ical_date which unset the date.
+- #277420 Add missing format information for minutes and seconds to date_sql_handler.
+- Make sure the timezone always goes on its own line now that date elements float.
+- #279932 Remove length from integer rows so they don't create errors in postgres.
+- #270316 Fix postgres timezone adjustment.
+- #279051 Fix postgres timezone test.
+- Add week handling and granularity tests to date_sql_handler().
+- Set date prefix on date navigation css classes.
+- Fix PHP4 handler for date_timezone_set() which was incorrectly altering the timestamp value.
+- Fix computation of 'N' in PHP4 date_format() wrapper to get date_week() working right in PHP4.
+- #274403 Fix typo in date_hours().
+- #269834 Add timezone adjustment to PHP4 date_format() wrapper.
+- #272110 Alter css so that from/to dates can float next to each other.
+- #275490 Remove orphaned punctuation at beginning of string in date_limit_format().
+- #277549 Make sure no repeats are created if no start date was set.
+- #272523 Fix error in PHP4 wrapper code that kept date_modify from working reliably.
+- #273344 Make sure incomplete Date Popup values get converted into complete dates.
+- #274882 Fix typo using $field instead of $form_values.
+- #276544 Rework system for handling timezone in date theme.
+- Add code to adjust NOW() by a number of seconds to allow NOW() to be the beginning of the day.
+- Rework PHP4 date handling to avoid any use of date() or mktime(), which may inject an incorrect timezone offset.
+- Get rid of the adodb method of computing the gmt offset for PHP4 and use the date_offset_get() computation.
+- Fix use of wrong value for timezone in repeating dates.
+- Remove as many dependencies as possible from install files and auto-enable necessary modules.
+- #270267 Remove timezone_identifiers_list() in the install file from the global space.
+- Date Popup was not handling empty non-required values correctly and they were defaulting to current date.
+- #273727 Small fixes to field settings validation.
+- #248338 and #254819 clean up date_limit_format() to better handle punctuation and escaped letters.
+- The jQuery calendar requires year, month, and day or it won't work, add validation for that in the settings.
+- #270358 Fix handling of year-only or month-only text fields to save the right values.
+- Remove unneeded hook_form_alter() used to fix radio values for granularity.
+- Make sure granularity is in correct format before setting value in field settings form.
+- #244025 Didn't get the right code into the original commit for the single jquery class.
+ Still have the problem that it won't work with AHAH add more.
+- #273130 Conform to new Drupal 6 method of indicating long and short month names.
+- Clean up Date popup validation.
+- Add templates for ical vevent and valarm.
+- Fix undefined indexes in date_repeat_calc.inc.
+- Change method of showing multiple values with timezones on forms and show them in every instance.
+ This is to simplify the processing and avoid errors when trying to apply the timezone in the
+ first item to all other items.
+- #272597 Remove php tag from timezone.js.
+- #272551 Add option to expand or collapse repeating date options.
+- #261610 Prepare for a jQuery popup in the calendar by adding a unique id to the 'node'
+ and altering the date theme to surpress all other dates if $node->date_id is set.
+- #232959 Get rid of unwanted scrollbars in date fieldsets using trick discovered by threexk.
+- Clean up install file included files and include file paths, and auto-enable date_timezone and date_php4.
+- Add a is_string() test to the date_is_valid() function.
+- The timezone element can sometimes be a nested value.
+- Date_fuzzy_date was not handling input from date_popup or date_text in the right way.
+- #260611 Replace substr with drupal_substr where used to get month and day abbreviations.
+- The granularity options were not saved correctly by CCK when provided as checkboxes, change them back to a select widget and fix the bad values in an update.
+- Have the date_text element handle its own format description instead of doing it in the Date module.
+- #270304 Timezone was not getting saved.
+- Empty values were getting saved.
+- #257353 No need for format description when using select widget.
+- #270267 Auto-enable the Date PHP4 module when needed.
+- #269569 Get the Date Views filter working.
+- #270626 Fix documentation errors that use create_date() instead of date_create().
+
+Version 6.2-beta3
+=================
+- #269569 Get new generic date filter working again.
+- Add a default view for the Date Browser.
+- Fix undefined indexes and add ability to override style in the Date Browser navigation attachment.
+- Add RRULE to ical template. Make sure all event values get added into the ical feed.
+- Get rid of date_ical_export(). The ical export code has been moved into a template and pre_processor.
+- Make Date API changes needed to get iCal export working in Calendar.
+- #251830 Replace D5 function name with D6 function name, content_alter_db_field() is D5 only.
+
+Version 6.2 beta2
+=================
+- Fix computation of week range computed from views arguments.
+- Now that a current date argument has been added to Views, remove the current date plugin from the Date API views handling.
+- #263377 Re-fix patch that I broke in later commit.
+- Comment out RRULE temporarily until repeating rules are fixed.
+- Omit the timezone from the process to store the current date parts in the form.
+- Change expected form values to match latest changes in CCK admin form.
+- #261631 No longer using $append, so get rid of it.
+- More work to ensure all the right timezone files are available in installations and updates.
+- Add theme folders to 6.2 branch.
+- #262272 Make sure $account is set before trying to use it in hook_user.
+- #263078 Fix error in setting up db session info that was triggering the MYSQL code for POSTGRES.
+- Move lots of similar date handling and navigation code out of Date and Calendar and into the Date API where we can use the same code everywhere.
+- Add a flexible date argument to the API that will work on any Views date field and take any ISO date argument.
+- Add an argument default option to set a missing date argument to the current date that will work on any date field.
+- Add a date back/next navigation attachment that works with the date argument and which can be attached to any view.
+- Adapt the Calendar module to share this code instead of creating its own.
+- Add calendar week calculations to the Date API so we can move them out of Calendar module to be able to use them in any date application.
+- Fix critical typo in date_get_timezone() that set the timezone to the site timezone even if it isn't right.
+- #257764 Replace hard-coded field and instance tablenames with the new content module function.
+- #130689 Move include code in the install file into a function and out of the global scope.
+- Fixes needed to display the timezone when that format is selected, and to pull the timezone out of format strings.
+- Date with timezone wasn't displaying the timezone selector.
+- #261628 fix typo in #process.
+- Change to sql handling from latest updates to the Calendar module.
+
+Version 6.2 beta
+================
+- #255911 node_submit() is not necessary for data integrity check.
+- Rename date.views.inc and change handling to new Views auto-include method.
+- Fix for critical flaw in the new timezone list handling that was creating an invalid array.
+- #257874 and #187599 provide a way to generate field content for the devel module.
+- Bad typo in date column type.
+- Fix install errors.
+- #255166 fix copy/paste error in date_token function name.
+- Working in a new sql handler class so we can use the same class in both.
+- Update date copy to convert either version 1 or version 2 Event nodes.
+- Add missing strtotime validation and format help text to textfield date and clarify that it's really a custom input format (which uses strtotime if the custom input fails).
+- Change method of getting translations for all timezones into the install file.
+- #256079 make translation of abbreviations easier.
+- #254930 fix parse error.
+- #238794, #254851 fix call-time pass-by-reference error.
+- #256078 Fix typo in popup calendar.
+- #255739 Fix backwards validation message when testing that the To date is greater than the From date.
+- Make sure anonymous users don't see timezone message.
+- Prepare for proposed core timezone handling from #11077 by getting rid of deprecated timezones and adding in js timezone name detection.
+- Rework default timezone handling to force a valid date even when timezones are not set to get rid of numerous installation and operational errors caused by invalid date objects.
+- Update site timezone offset during cron and user offset during login to make sure that modules that rely on the timezone offset have current information to process when the offset changes.
+- #251511 Rename function to avoid clash with Diff module.
+- Rework the date filter and argument -- simplify some of the code but still keep as much flexibility as possible. You can set up the filter to provide either a date or offset selector (or both), you can set the granularity of the date parts, and any part can be set to all all values, the current time, or a specific value for either a single date or a from/to combination.
+- #250813 Make sure Views handlers are initiated.
+- #244708 menu code cleanup.
+- Clean up timezone handling in date repeat logic.
+- #234021 fix date_repeat timestamp errors.
+- #234102 It turns out that we must always force use of the lower level date functions because regular strtotime and mktime can be off by one hour during daylight savings time.
+- #234073 Provide a way to make required textfield start out with blank values.
+- #239900, #249399 Limit available formats for Date Popup to available formats and hide custom format code which won't work right here.
+- Can't use date_make_date within date_part_extract without setting up potential circular reference.
+- Format_interval logic was backwards.
+- #236889 Make sure date_select validation only checks required granularity.
+- #234073 Provide a way to make a required date start out with blank values.
+- #247749 don't use date popup on system date form, too many potential conflicts.
+- #234360 fix date_server_zone_adj() function.
+- #242433 adjust timestamps to datetime when creating repeating dates.
+- #233415 separate ical retrieval and parser so other modules like feedapi can use the parser alone.
+- #240980 coder compliance fixups.
+- #225738 Add special case handling for year only or year and month only ISO dates.
+- #244025 make the jquery calendar code more efficient.
diff --git a/sites/all/modules/date/INSTALL.txt b/sites/all/modules/date/INSTALL.txt
new file mode 100644
index 0000000..0afc591
--- /dev/null
+++ b/sites/all/modules/date/INSTALL.txt
@@ -0,0 +1,71 @@
+==================================================================================
+Date API Installation instructions:
+==================================================================================
+1) If you have an earlier version of the Date module on your system, empty the
+ date folder out completely. The files in version 2 have different names and are
+ located in different places.
+
+2) Download the whole package of files from http://drupal.org/project/date.
+
+3) Upload the date files to the modules directory. The package includes files
+ needed by the Date API, and optional modules to to create CCK date fields.
+
+4) Go to admin/build/modules and enable the needed modules from the Date/Time group.
+
+You should end up with a structure like:
+
+ /drupal/sites/all/modules/date/date_api.info
+ /drupal/sites/all/modules/date/date_api.install
+ /drupal/sites/all/modules/date/date_api.module
+ ...
+
+ /drupal/sites/all/modules/date/date/date.info
+ /drupal/sites/all/modules/date/date/date.install
+ /drupal/sites/all/modules/date/date/date.module
+ ...
+
+ /drupal/sites/all/modules/date/date_copy/date_copy.info
+ /drupal/sites/all/modules/date/date_copy/date_copy.module
+ ...
+
+ /drupal/sites/all/modules/date/date_php4/date_php4.inc
+ /drupal/sites/all/modules/date/date_php4/date_php4_lib.inc
+ ...
+
+==================================================================================
+Older PHP versions
+==================================================================================
+If you are using PHP 4 or PHP 5.0 or 5.1, native date handling won't work right.
+Install the Date_PHP4 module to enable wrapper functions so this code will work
+in old PHP versions.
+
+==================================================================================
+Enable Date Timezone
+==================================================================================
+In most cases, you should enable the Date Timezone module any time you use the
+Date API to be able to set the site and user timezone names. It is not enabled by
+default in case another module is setting timezone names in the database.
+
+Once you have enabled it, go to admin/settings/date-time and set the default
+site timezone name. If you are using user timezones, go to your account settings
+and set up your own timezone name.
+
+==================================================================================
+Install CCK Date Fields:
+==================================================================================
+
+1) The CCK date field is included in the Date files at http://drupal.org/project/date.
+
+2) Go to admin/build/modules and enable the Date module. Be sure that the Date API module,
+ the Date Timezone module, and the Content module are also installed.
+
+3) Go to admin/content/types to view cck content types and edit a content type.
+
+4) Make sure the default timezone name has been set at admin/settings/date-time.
+
+5) While viewing a content type, select the option to add a new field from the tabs at
+ the top of the page. Several options for date fields should be visible.
+
+==================================================================================
+More documentation is available at http://drupal.org/node/92460.
+==================================================================================
diff --git a/sites/all/modules/date/LICENSE.txt b/sites/all/modules/date/LICENSE.txt
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/sites/all/modules/date/LICENSE.txt
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/sites/all/modules/date/README.txt b/sites/all/modules/date/README.txt
new file mode 100644
index 0000000..cb404e0
--- /dev/null
+++ b/sites/all/modules/date/README.txt
@@ -0,0 +1,307 @@
+INFORMATION FOR DEVELOPERS
+
+Once the Date API is installed, all functions in the API are available to be used
+anywhere by any module. If the Date Timezone module is installed, the system site
+timezone selector and the user timezone selectors are overwritten to allow the
+selection of timezone names instead of offsets. Proper timezone conversion
+requires knowledge of those timezone names, something that is not currently
+available in Drupal core, and the change in selectors makes it possible to track it.
+
+In most cases, you should enable the Date Timezone module any time you use the
+Date API to be able to set the site and user timezone names. It is not enabled by
+default in case another module is setting timezone names in the database.
+
+The API uses the PHP 5.2 date functions to create and manipulate dates, and
+contains an option module that will emulate those functions in earlier versions
+of PHP.
+
+If you are using PHP 4 or PHP 5.0 or 5.1, native date handling won't work right.
+Install the Date_PHP4 module to enable wrapper functions so this code will work
+in old PHP versions.
+
+Example, the following will create a date for the local value in one
+timezone, adjust it to a different timezone, then return the offset in seconds
+in the new timezone for the input date; The offset will be adjusted for both
+the timezone difference and daylight savings time, if necessary:
+
+$date = date_create('2007-03-11 02:00:00', timezone_open('America/Chicago'));
+$chicago_time = date_format($date, 'Y-m-d H:i');
+
+print 'At '. $chicago_time .' in Chicago, the timezone offset in seconds
+ was '. date_offset_get($date);
+
+date_timezone_set($date, timezone_open('Europe/Berlin');
+$berlin_time = date_format($date, 'Y-m-d H:i');
+
+print 'It was '. $berlin_time .' in Berlin when it
+ was '. $chicago_time .' in Chicago.';
+print 'At that time in Berlin, the timezone offset in seconds was
+ '. date_offset_get($date);
+
+A helper function is available, date_make_date($string, $timezone, $type),
+where $string is a unixtimestamp, an ISO date, or a string like YYYY-MM-DD HH:MM:SS,
+$timezone is the name of the timezone this date is in, and $type is the type
+of date it is (DATE_UNIX, DATE_ISO, or DATE_DATETIME). It create and return
+a date object set to the right date and timezone.
+
+Simpletest tests for these functions are included in the package.
+
+Available functions include the following (more documentation is provided in
+the files):
+
+============================================================================
+Date PHP4 Module
+============================================================================
+PHP 4 substitutions for the PHP 5 date functions are supplied. Use the PHP 5
+functions in your code as they would normally be used and the PHP 4
+alternatives will be automatically be substituted in when needed.
+
+You cannot do everything with these functions that can be done in PHP 5, but
+you can create dates, find timezone offsets, and format the results.
+Timezone handling uses native PHP 5 functions when available and degrades
+automatically for PHP 4 to use substitutions like those
+provided in previous versions of the Date and Event modules.
+
+Read the doxygen documentation in this module for more information
+about using the functions in ways that will work in PHP 4.
+
+Simpletest tests for the PHP 4 equivalent functions are included in the package.
+
+The following functions are emulated in PHP4:
+date_create()
+date_date_set()
+date_format()
+date_offset_get()
+date_timezone_set()
+timezone_abbreviations_list()
+timezone_identifiers_list()
+timezone_offset_get()
+timezone_open()
+
+============================================================================
+Preconfigured arrays
+============================================================================
+Both translated and untranslated values are available. The date_week_days_ordered()
+function will shift an array of week day names so it starts with the site's
+first day of the week, otherwise the weekday names start with Sunday as the first
+value, the expected order for many php and sql functions.
+
+date_month_names();
+date_month_names_abbr();
+date_month_names_untranslated();
+date_week_days();
+date_week_days_abbr();
+date_week_days_untranslated();
+date_week_days_ordered();
+date_years();
+date_hours();
+date_minutes();
+date_seconds();
+date_timezone_names();
+date_ampm();
+
+============================================================================
+Miscellaneous date manipulation functions
+============================================================================
+Pre-defined constants and functions that will handle pre-1970 and post-2038
+dates in both PHP 4 and PHP 5, in any OS. Dates can be converted from one
+type to another and date parts can be extracted from any date type.
+
+DATE_DATETIME
+DATE_ISO
+DATE_UNIX
+DATE_ARRAY
+DATE_OBJECT
+DATE_ICAL
+
+date_convert()
+date_is_valid();
+date_part_is_valid();
+date_part_extract();
+
+============================================================================
+Date calculation and navigation
+============================================================================
+date_difference() will find the time difference between any two days, measured
+in seconds, minutes, hours, days, months, weeks, or years.
+
+date_days_in_month();
+date_days_in_year();
+date_weeks_in_year();
+date_last_day_of_month();
+date_day_of_week();
+date_day_of_week_name();
+date_difference();
+
+============================================================================
+Date regex and format helpers
+============================================================================
+Pre-defined constants, an array of date format strings and their
+equivalent regex strings.
+
+DATE_REGEX_LOOSE is a very loose regex that will pull date parts out
+of an ISO date with or without separators, using either 'T' or a space
+to separate date and time, and with or without time.
+
+date_format_date() is similar to format_date(), except it takes a
+date object instead of a timestamp as the first parameter.
+
+DATE_FORMAT_ISO
+DATE_FORMAT_DATETIME
+DATE_FORMAT_UNIX
+DATE_FORMAT_ICAL
+
+DATE_REGEX_ISO
+DATE_REGEX_DATETIME
+DATE_REGEX_LOOSE
+
+date_format_date();
+date_t()
+date_short_formats();
+date_medium_formats();
+date_long_formats();
+date_format_patterns();
+
+============================================================================
+Standardized ical parser and creator
+============================================================================
+The iCal parser is found in date_api_ical.inc, which is not included by default.
+Include that file if you want to use these functions:
+
+Complete rewrite of ical imports to parse vevents, vlocations, valarms,
+and all kinds of timezone options and repeat rules for ical imports.
+The function now sticks to parsing the ical into an array that can be used
+in various ways. It no longer trys to convert timezones while parsing,
+instead a date_ical_date_format() function is provided that can be used to
+convert from the ical timezone to whatever timezone is desired in the
+results. Repeat rules are parsed into an array which other modules can
+manipulate however they like to create additional events from the results.
+
+date_ical_export();
+date_ical_import();
+date_ical_date_format();
+
+============================================================================
+Helpers for portable date SQL
+============================================================================
+The SQL functions are found in date_api_sql.inc, which is not included by default.
+Include that file if you want to use these functions:
+
+date_sql();
+date_server_zone_adj();
+date_sql_concat();
+date_sql_pad();
+
+============================================================================
+Date forms and validators
+============================================================================
+Reusable, configurable, self-validating FAPI date elements are found in
+date_api_elements.inc, which is not included by default. Include it
+if you want to use these elements. To use them, create a form element
+and set the '#type' to one of the following:
+
+date_select
+ The date_select element will create a collection of form elements, with a
+ separate select or textfield for each date part. The whole collection will
+ get re-formatted back into a date value of the requested type during validation.
+
+date_text
+ The date_text element will create a textfield that can contain a whole
+ date or any part of a date as text. The user input value will be re-formatted
+ back into a date value of the requested type during validation.
+
+date_timezone
+ The date_timezone element will create a drop-down selector to pick a
+ timezone name.
+
+The custom date elements require a few other pieces of information to work
+correctly, like #date_format and #date_type. See the internal documentation
+for more information.
+
+============================================================================
+Date Popup Module
+============================================================================
+
+A new module is included in the package that will enable a popup jQuery
+calendar date picker and timepicker in date and time fields.
+
+It is implemented as a custom form element, so set '#type' to 'date_popup'
+to use this element. See the internal documentation for more information.
+
+============================================================================
+Date Repeat API
+============================================================================
+
+An API for repeating dates is available if installed. It can be used by
+other modules to create a form element that will allow users to select
+repeat rules and store those selections in an iCal RRULE string, and a
+calculation function that will parse the RRULE and return an array of dates
+that match those rules. The API is implemented in the Date module as a
+new date widget if the Date Repeat API is installed.
+
+============================================================================
+Install file for dependent modules
+============================================================================
+
+The following code is an example of what should go in the .install file for
+any module that uses the new Date API. This is needed to be sure the system
+is not using an earlier version of the API that didn't include all these new
+features. Testing for version '5.2' will pick up any version on or after the
+change to the new API.
+
+/**
+ * Implementation of hook_requirements().
+ */
+function calendar_requirements($phase) {
+ $requirements = array();
+ $t = get_t();
+
+ // This is the minimum required version for the Date API so that it will
+ work with this module.
+ $required_version = 5.2;
+
+ // Make sure the matching version of date_api is installed.
+ // Use info instead of an error at install time since the problem may
+ // just be that they were installed in the wrong order.
+ switch ($phase) {
+ case 'runtime':
+ if (variable_get('date_api_version', 0) < $required_version) {
+ $requirements['calendar_api_version'] = array(
+ 'title' => $t('Calendar requirements'),
+ 'value' => $t('The Calendar module requires a more current version
+ of the Date API. Please check for a newer version.'),
+ 'severity' => REQUIREMENT_ERROR,
+ );
+ }
+ break;
+ case 'install':
+ if (variable_get('date_api_version', 0) < $required_version) {
+ $requirements['calendar_api_version'] = array(
+ 'title' => $t('Calendar requirements'),
+ 'value' => $t('The Calendar module requires the latest version
+ of the Date API, be sure you are installing the latest versions
+ of both modules.'),
+ 'severity' => REQUIREMENT_INFO,
+ );
+ }
+ break;
+ }
+ return $requirements;
+}
+
+/**
+ * Implementation of hook_install().
+ */
+function calendar_install() {
+ // Make sure this module loads after date_api.
+ db_query("UPDATE {system} SET weight = 1 WHERE name = 'calendar'");
+}
+
+/**
+ * Implementation of hook_update().
+ */
+function calendar_update_5000() {
+ $ret = array();
+ $ret[] = update_sql("UPDATE {system} SET weight = 1 WHERE name = 'calendar'");
+ return $ret;
+}
diff --git a/sites/all/modules/date/date-rtl.css b/sites/all/modules/date/date-rtl.css
new file mode 100644
index 0000000..7d415dc
--- /dev/null
+++ b/sites/all/modules/date/date-rtl.css
@@ -0,0 +1,33 @@
+.container-inline-date {
+ margin-left: 0.5em;
+ margin-right: 0;
+}
+.container-inline-date .form-item .form-item {
+ float: right;
+}
+
+.container-inline-date .form-item input,
+.container-inline-date .form-item select,
+.container-inline-date .form-item option {
+ margin-left: 5px;
+ margin-right: 0;
+}
+
+.container-inline-date .date-spacer {
+ margin-left: 0;
+ margin-right: -5px;
+}
+
+.date-nav div.date-prev {
+ text-align: right;
+ float: right;
+}
+
+.date-nav div.date-next {
+ text-align: left;
+ float: right;
+}
+
+.date-nav div.date-heading {
+ float: right;
+}
diff --git a/sites/all/modules/date/date.css b/sites/all/modules/date/date.css
new file mode 100644
index 0000000..2db7b32
--- /dev/null
+++ b/sites/all/modules/date/date.css
@@ -0,0 +1,206 @@
+/* Force from/to dates to float using inline-block, where it works, otherwise inline. */
+.container-inline-date {
+ width:auto;
+ clear:both;
+ display: inline-block;
+ vertical-align:top;
+ margin-right: 0.5em; /* LTR */
+}
+.container-inline-date .form-item {
+ float:none;
+ padding:0;
+ margin:0;
+}
+.container-inline-date .form-item .form-item {
+ float: left; /* LTR */
+}
+.container-inline-date .form-item,
+.container-inline-date .form-item input {
+ width:auto;
+}
+.container-inline-date .description {
+ clear: both;
+}
+
+.container-inline-date .form-item input,
+.container-inline-date .form-item select,
+.container-inline-date .form-item option {
+ margin-right: 5px; /* LTR */
+}
+
+.container-inline-date .date-spacer {
+ margin-left: -5px; /* LTR */
+}
+.views-right-60 .container-inline-date div {
+ padding:0;
+ margin:0;
+}
+
+.container-inline-date .date-timezone .form-item {
+ float:none;
+ width:auto;
+ clear:both;
+}
+
+/* Fixes for date popup css so it will behave in Drupal */
+#calendar_div, #calendar_div td, #calendar_div th {
+ margin:0;
+ padding:0;
+}
+#calendar_div,
+.calendar_control,
+.calendar_links,
+.calendar_header,
+.calendar {
+ width: 185px;
+ border-collapse: separate;
+ margin: 0;
+}
+.calendar td {
+ padding: 0;
+}
+
+/* formatting for from/to dates in nodes and views */
+span.date-display-single {
+}
+span.date-display-start {
+}
+span.date-display-end {
+}
+span.date-display-separator {
+}
+
+.date-repeat-input {
+ float: left; /* LTR */
+ width:auto;
+ margin-right: 5px; /* LTR */
+}
+.date-repeat-input select {
+ min-width:7em;
+}
+.date-repeat fieldset {
+ clear:both;
+ float:none;
+}
+
+.date-views-filter-wrapper {
+ min-width:250px;
+}
+.date-views-filter input {
+ float: left !important; /* LTR */
+ margin-right: 2px !important; /* LTR */
+ padding:0 !important;
+ width:12em;
+ min-width:12em;
+}
+
+.date-nav {
+ width:100%;
+}
+.date-nav div.date-prev {
+ text-align: left; /* LTR */
+ width:24%;
+ float: left; /* LTR */
+}
+.date-nav div.date-next {
+ text-align: right; /* LTR */
+ width:24%;
+ float: right; /* LTR */
+}
+.date-nav div.date-heading {
+ text-align:center;
+ width:50%;
+ float: left; /* LTR */
+}
+.date-nav div.date-heading h3 {
+ margin:0;
+ padding:0;
+}
+
+.date-clear {
+ float:none;
+ clear:both;
+ display:block;
+}
+
+.date-clear-block {
+ float:none;
+ width:auto;
+ clear:both;
+}
+
+/*
+ ** Markup free clearing that fixes unwanted scrollbars
+ ** @see http://drupal.org/node/232959
+ */
+ .date-clear-block:after {
+ content: " ";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+ }
+ .date-clear-block {
+ display: inline-block;
+ }
+ /* Hides from IE-mac \*/
+ * html .date-clear-block {
+ height: 1%;
+ }
+ .date-clear-block {
+ display: block;
+ }
+ /* End hide from IE-mac */
+
+.date-container .date-format-delete {
+ margin-top: 1.8em;
+ margin-left: 1.5em;
+ float: left;
+}
+.date-container .date-format-name {
+ float: left;
+}
+.date-container .date-format-type {
+ float: left;
+ padding-left: 10px;
+}
+
+.date-container .select-container {
+ clear: left;
+ float: left;
+}
+
+/* Calendar day css */
+div.date-calendar-day {
+ line-height: 1;
+ width: 40px;
+ float: left;
+ margin: 6px 10px 0 0;
+ background: #F3F3F3;
+ border-top: 1px solid #eee;
+ border-left: 1px solid #eee;
+ border-right: 1px solid #bbb;
+ border-bottom: 1px solid #bbb;
+ color: #999;
+ text-align: center;
+ font-family: Georgia, Arial, Verdana, sans;
+}
+div.date-calendar-day span {
+ display: block;
+ text-align: center;
+}
+div.date-calendar-day span.month {
+ font-size: .9em;
+ background-color: #B5BEBE;
+ color: white;
+ padding: 2px;
+ text-transform: uppercase;
+}
+div.date-calendar-day span.day {
+ font-weight: bold;
+ font-size: 2em;
+}
+div.date-calendar-day span.year {
+ font-size: .9em;
+ padding: 2px;
+}
diff --git a/sites/all/modules/date/date/date.info b/sites/all/modules/date/date/date.info
new file mode 100644
index 0000000..2ba71da
--- /dev/null
+++ b/sites/all/modules/date/date/date.info
@@ -0,0 +1,13 @@
+name = Date
+description = Defines CCK date/time fields and widgets.
+dependencies[] = content
+dependencies[] = date_api
+dependencies[] = date_timezone
+package = Date/Time
+core = 6.x
+; Information added by Drupal.org packaging script on 2014-03-31
+version = "6.x-2.10"
+core = "6.x"
+project = "date"
+datestamp = "1396284252"
+
diff --git a/sites/all/modules/date/date/date.install b/sites/all/modules/date/date/date.install
new file mode 100644
index 0000000..e189efc
--- /dev/null
+++ b/sites/all/modules/date/date/date.install
@@ -0,0 +1,457 @@
+ 'year'
+ * 'month' => 'month',
+ * 'day' => 0,
+ * 'hour' => 0,
+ * 'minute' => 0,
+ * 'second' => 0,
+ * );
+ *
+ * Good values would have been stored in the form
+ * array(
+ * 'year' => 'year',
+ * 'month' => 'month',
+ * );
+ *
+ * This might or might not have gotten updated in D5.2,
+ * we need to force it again in D6 just in case.
+ *
+ * @return unknown
+ */
+function date_update_6000() {
+ include_once(drupal_get_path('module', 'content') .'/content.install');
+ if ($abort = content_check_update('date')) {
+ return $abort;
+ }
+ drupal_load('module', 'content');
+ $ret = array();
+ $result = db_query("SELECT field_name, global_settings from {". content_field_tablename() ."} where type LIKE 'date_%'");
+ while ($field = db_fetch_array($result)) {
+ // Change the format to one date_popup can use.
+ $field_settings = unserialize($field['global_settings']);
+ $granularity = array_filter($field_settings['granularity']);
+ $field_settings['granularity'] = $granularity;
+ db_query("UPDATE {". content_field_tablename() ."} SET global_settings = '%s' WHERE field_name = '%s'", serialize($field_settings), $field['field_name']);
+ }
+ content_clear_type_cache();
+ return $ret;
+}
+
+/**
+ * Get rid of jscalendar popup widget.
+ * Originally update_5201, but that was broken.
+ */
+function date_update_6001() {
+ include_once(drupal_get_path('module', 'content') .'/content.install');
+ if ($abort = content_check_update('date')) {
+ return $abort;
+ }
+ drupal_load('module', 'content');
+ $ret = array();
+ if (db_result(db_query("SELECT COUNT(*) FROM {". content_instance_tablename() ."} WHERE widget_type = 'date_js'"))) {
+ $replace = module_exists('date_popup') ? 'date_popup' : 'date_text';
+ $result = db_query("SELECT field_name, type_name, widget_type from {". content_instance_tablename() ."} where widget_type = 'date_js'");
+ while ($widget = db_fetch_array($result)) {
+ db_query("UPDATE {". content_instance_tablename() ."} SET widget_type = '$replace' WHERE field_name = '%s' AND type_name = '%s'", $widget['field_name'], $widget['type_name']);
+ }
+ drupal_set_message(t('All date fields using the jscalendar widget have been changed to use the text widget instead, since the jscalendar widget is no longer supported. Enable the Date Popup module to make a jQuery popup calendar available and edit the field settings to select it.'));
+ content_clear_type_cache();
+ }
+ return $ret;
+}
+
+/**
+ * Switch to using different widgets for repeating dates so non-repeats
+ * can use standard Content module multiple values handling.
+ */
+function date_update_6002() {
+ include_once(drupal_get_path('module', 'content') .'/content.install');
+ if ($abort = content_check_update('date')) {
+ return $abort;
+ }
+ drupal_load('module', 'content');
+ $ret = array();
+ $types = content_types();
+ $repeating_fields = array();
+ foreach ($types as $type) {
+ foreach ($type['fields'] as $field_name => $field) {
+ if (!empty($field['repeat'])) {
+ $repeating_fields[] = $field_name;
+ }
+ }
+ }
+ if (count($repeating_fields)) {
+ $replace = array(
+ 'date_select' => 'date_select_repeat',
+ 'date_text' => 'date_text_repeat',
+ 'date_popup' => 'date_popup_repeat',
+ );
+ $result = db_query("SELECT * from {". content_instance_tablename() ."} WHERE widget_type IN('date_select', 'date_text', 'date_popup') AND field_name IN('". implode("','", $repeating_fields) ."')");
+ while ($widget = db_fetch_array($result)) {
+ db_query("UPDATE {". content_field_tablename() ."} SET multiple = 1 WHERE field_name = '%s'", $widget['field_name']);
+ db_query("UPDATE {". content_instance_tablename() ."} SET widget_type = '". $replace[$widget['widget_type']] ."' WHERE field_name = '%s' AND type_name = '%s'", $widget['field_name'], $widget['type_name']);
+ }
+ drupal_set_message(t('All repeating date fields have been updated to use the new repeating widgets.'));
+ content_clear_type_cache();
+ }
+ return $ret;
+}
+
+/**
+ * Update all repeating date delta values with the RRULE
+ * so we can use that info in Views when we pull individual items
+ * out in a query.
+ */
+function date_update_6003() {
+ $ret = array();
+ drupal_load('module', 'content');
+ $fields = content_fields();
+ foreach ($fields as $field) {
+ if (strstr($field['type'], 'date') && !empty($field['repeat'])) {
+ $db_info = content_database_info($field);
+ $table = $db_info['table'];
+ $column = $field['field_name'] .'_rrule';
+ $result = db_query("SELECT DISTINCT nid, vid, $column FROM {". $table ."} WHERE $column <> ''");
+ while ($row = db_fetch_array($result)) {
+ $ret[] = update_sql("UPDATE {". $table ."} SET $column='". $row[$column] ."' WHERE nid=". $row['nid'] ." AND vid=". $row['vid']);
+ }
+ }
+ }
+ return $ret;
+}
+
+/**
+ * Empty the stored db for timezones that use timezone 'none'.
+ */
+function date_update_6004() {
+ $ret = array();
+ drupal_load('module', 'content');
+ $fields = content_fields();
+ foreach ($fields as $field) {
+ if (strstr($field['type'], 'date') && !empty($field['tz_handling']) && $field['tz_handling'] == 'none') {
+ $row = db_result(db_query("SELECT global_settings FROM {". content_field_tablename() ."} WHERE field_name='". $field['field_name'] ."'"));
+ $settings = unserialize($row);
+ $settings['timezone_db'] = '';
+ $settings = serialize($settings);
+ db_query("UPDATE {". content_field_tablename() ."} SET global_settings='%s' WHERE field_name='%s'", $settings, $field['field_name']);
+ }
+ }
+ drupal_set_message(t("The database has been updated to correct the stored timezone for fields using timezone 'none'."));
+ content_clear_type_cache();
+ return $ret;
+}
+
+function date_update_6005() {
+ include_once(drupal_get_path('module', 'content') .'/content.install');
+ if ($abort = content_check_update('date')) {
+ return $abort;
+ }
+ // The new format table won't get built before the system tries to run this update.
+ // We need to abort and tell the user to re-run it.
+ // We need a custom abort process because the content_check_update could be OK
+ // but we still need to update these values.
+ if ((!db_table_exists('date_format') && !db_table_exists('date_formats')) || !db_table_exists('date_format_types')) {
+ drupal_set_message(t('Some updates are still pending. Please return to update.php and run the remaining updates.', array('@update-php' => base_path() .'update.php?op=selection')), 'error', FALSE);
+ $ret['#abort'] = array('success' => FALSE, 'query' => t('Some updates are still pending. Please re-run the update script.'));
+ return $ret;
+ }
+ drupal_load('module', 'content');
+ $ret = array();
+
+ $new_map = array(
+ 'short' => 'short',
+ 'medium' => 'medium',
+ 'long' => 'long',
+ 'time' => 'time',
+ 'time_timezone' => 'time_timezone',
+ 'iso' => 'iso',
+ 'timestamp' => 'timestamp',
+ 'ical' => 'ical',
+ 'feed' => 'feed',
+ );
+
+ // Create new custom formats for each of these:
+ date_install_create_format(NULL, t('Time'), 'time', date_limit_format(variable_get('date_format_short', 'm/d/Y - H:i'), array('hour', 'minute', 'second')));
+ date_install_create_format(NULL, t('Time with timezone'), 'time_timezone', date_limit_format(variable_get('date_format_short', 'm/d/Y - H:i') .' e', array('hour', 'minute', 'second', 'timezone')));
+ date_install_create_format(NULL, t('iCal'), 'ical', 'Ymd\THis');
+ date_install_create_format(NULL, t('Timestamp'), 'timestamp', 'U');
+ date_install_create_format(NULL, t('Feed'), 'feed', 'D, j M Y H:i:s O');
+ date_install_create_format(NULL, t('ISO'), 'iso', DATE_FORMAT_ISO);
+
+ $result = db_query("SELECT field_name, global_settings from {". content_field_tablename() ."} where type='date' OR type='datestamp' OR type='datetime'");
+ while ($field = db_fetch_array($result)) {
+ $field_settings = unserialize($field['global_settings']);
+ $field_name = $field['field_name'];
+
+ $default = !empty($field_settings['output_format_custom']) ? $field_settings['output_format_custom'] : $field_settings['output_format_date'];
+ $short = !empty($field_settings['output_format_custom_short']) ? $field_settings['output_format_custom_short'] : $field_settings['output_format_date_short'];
+ $med = !empty($field_settings['output_format_custom_medium']) ? $field_settings['output_format_custom_medium'] : $field_settings['output_format_date_medium'];
+ $long = !empty($field_settings['output_format_custom_long']) ? $field_settings['output_format_custom_long'] : $field_settings['output_format_date_long'];
+ $system_short = variable_get('date_format_short', 'm/d/Y - H:i');
+ $system_med = variable_get('date_format_medium', 'D, m/d/Y - H:i');
+ $system_long = variable_get('date_format_long', 'l, F j, Y - H:i');
+
+ // The only thing we'll keep is the name of a default format type.
+ $new_setting = 'default_format';
+
+ // Create a map of the old and new formats.
+ $map = $new_map;
+
+ // If the field's long, medium, or short formats don't match the system
+ // values, create custom format types for them.
+
+ // If the default value matches a custom format, set that new format
+ // type as the default format type.
+
+ if ($system_short != $short) {
+ $name = $field_name .'_short';
+ date_install_create_format($field, NULL, $name, $short);
+ $map['short'] = $name;
+ if ($default == $short) {
+ $field_settings[$new_setting] = $name;
+ $map['default'] = $name;
+ }
+ }
+ if ($system_med != $med) {
+ $name = $field_name .'_medium';
+ date_install_create_format($field, NULL, $name, $med);
+ $map['medium'] = $name;
+ if ($default == $med) {
+ $field_settings[$new_setting] = $name;
+ $map['default'] = $name;
+ }
+ }
+ if ($system_long != $long) {
+ $name = $field_name .'_long';
+ date_install_create_format($field, NULL, $name, $long);
+ $map['long'] = $name;
+ if ($default == $long) {
+ $field_settings[$new_setting] = $name;
+ $map['default'] = $name;
+ }
+ }
+ // If we haven't found a format type for the default format yet,
+ // see if it matches any of the system formats.
+ if (empty($field_settings[$new_setting])) {
+ if ($default == $system_med) {
+ $field_settings[$new_setting] = 'medium';
+ $map['default'] = 'medium';
+ }
+ elseif ($default == $system_long) {
+ $field_settings[$new_setting] = 'long';
+ $map['default'] = 'long';
+ }
+ elseif ($default == $system_short) {
+ $field_settings[$new_setting] = 'short';
+ $map['default'] = 'short';
+ }
+ else {
+ // If all else fails, create a new format type
+ // for the default format.
+ $name = $field_name .'_default';
+ date_install_create_format($field, NULL, $name, $default);
+ $field_settings[$new_setting] = $name;
+ $map['default'] = $name;
+ }
+ }
+
+ // Store the map of old and new formats in a variable.
+ variable_set('date_format_map_'. $field['field_name'], $map);
+ $ret[] = array('success' => TRUE, 'query' => t('Field %field formats were converted to custom formats.', array('%field' => $field_name)));
+ foreach ($map as $key => $value) {
+ if (in_array($key, array('default', 'short', 'medium', 'long'))) {
+ $ret[] = array('success' => TRUE, 'query' => t("The old format type %from_format for field %field was converted to the new format type %to_format.", array('%field' => $field_name, '%from_format' => $key, '%to_format' => $value)));
+ }
+ }
+
+ // Unset all the old values, we won't use them any more.
+ unset($field_settings['output_format_date']);
+ unset($field_settings['output_format_custom']);
+ unset($field_settings['output_format_date_short']);
+ unset($field_settings['output_format_custom_short']);
+ unset($field_settings['output_format_date_medium']);
+ unset($field_settings['output_format_custom_medium']);
+ unset($field_settings['output_format_date_long']);
+ unset($field_settings['output_format_custom_long']);
+
+ db_query("UPDATE {". content_field_tablename() ."} SET global_settings = '%s' WHERE field_name = '%s'", serialize($field_settings), $field_name);
+
+ // Update the display settings to point to the new format types.
+ $result2 = db_query("SELECT * FROM {". content_instance_tablename() ."} WHERE field_name = '$field_name'");
+ while ($instance = db_fetch_array($result2)) {
+ $display_settings = unserialize($instance['display_settings']);
+ foreach ($display_settings as $key => $setting) {
+ if ($key != 'label' && array_key_exists($display_settings[$key]['format'], $map)) {
+ $display_settings[$key]['format'] = $map[$display_settings[$key]['format']];
+ }
+ }
+ db_query("UPDATE {". content_instance_tablename() ."} SET display_settings = '%s' WHERE field_name = '%s' AND type_name = '%s'", serialize($display_settings), $field_name, $instance['type_name']);
+ $ret[] = array('success' => TRUE, 'query' => t("The display settings for field %field in content type %type_name were updated.", array('%field' => $field_name, '%type_name' => $instance['type_name'])));
+ }
+
+ // See if any views stored in the database need date formats updated.
+ /*
+ $result2 = db_query("SELECT * FROM {views_display}");
+ while ($row = db_fetch_array($result2)) {
+ $updated = FALSE;
+ $display_options = unserialize($row['display_options']);
+ if (array_key_exists('fields', $display_options)) {
+ if (array_key_exists($field_name .'_value', $display_options['fields'])) {
+ $display_options['fields'][$field_name .'_value']['format'] = $map[$display_options['fields'][$field_name .'_value']['format']];
+ $updated = TRUE;
+ }
+ if (array_key_exists($field_name .'_value2', $display_options['fields'])) {
+ $display_options['fields'][$field_name .'_value2']['format'] = $map[$display_options['fields'][$field_name .'_value2']['format']];
+ $updated = TRUE;
+ }
+ if ($updated) {
+ db_query("UPDATE {views_display} SET display_options='%s'", serialize($display_options));
+ $ret[] = array('success' => TRUE, 'query' => t("The format used for field %field in view %vid %display display was updated to the new format name.", array('%field' => $field_name, '%display' => $row['display_title'], '%vid' => $row['vid'])));
+ }
+ }
+ }
+ */
+
+ }
+ // Clear any caches that may have old formats in them.
+ content_clear_type_cache();
+ drupal_set_message(t('Date display formats are now included with the system date and time settings. Please visit the Date and time format page to see the new format types.', array('@date-time-page' => url('admin/settings/date-time/formats'))));
+ return $ret;
+}
+
+function date_install_create_format($field, $title, $name, $format) {
+ if (empty($name) || empty($format)) {
+ return;
+ }
+ $fields = content_fields();
+ if (empty($title)) {
+ $type = str_replace($field['field_name'] .'_', '', $name);
+ $field = $fields[$field['field_name']];
+ $title = $field['widget']['label'];
+ }
+ variable_set('date_format_'. $name, $format);
+ db_query("INSERT INTO {date_format_types} (type, title, locked) VALUES('%s', '%s', 0)", $name, $title);
+ if (!db_result(db_query("SELECT dfid FROM {date_formats} WHERE format='%s' AND type='%s'", $format, $type))) {
+ db_query("INSERT INTO {date_formats} (format, type, locked) VALUES('%s', '%s', 0)", $format, 'custom');
+ }
+}
+
+function date_db_integrity($name) {
+ $ret = array();
+ if (!module_exists('content') || !module_exists('date_api')) {
+ return $ret;
+ }
+ drupal_load('module', 'content');
+ require_once('./'. drupal_get_path('module', 'content') .'/includes/content.admin.inc');
+ $ret = array();
+ $fields = content_fields();
+ foreach ($fields as $field) {
+ $db_info = content_database_info($field);
+ if ($field['type'] == 'date' || $field['type'] == 'datestamp') {
+ $table = $db_info['table'];
+
+ // start with the new column patterns.
+ $columns_start = $db_info['columns'];
+ $columns_end = $db_info['columns'];
+
+ // alter the start column values to invalid or empty
+ // values to force the new columns to be reset.
+ $columns_start['value']['length'] = 90;
+ if (!empty($field['todate'])) {
+ if (!db_column_exists($table, $columns_start['value2']['column'])) {
+ unset($columns_start['value2']);
+ }
+ else {
+ $columns_start['value2']['length'] = 80;
+ }
+ }
+ if ($field['tz_handling'] == 'date') {
+ if (!db_column_exists($table, $columns_start['timezone']['column'])) {
+ unset($columns_start['timezone']);
+ }
+ else {
+ $columns_start['timezone']['length'] = 80;
+ }
+ if (!db_column_exists($table, $columns_start['offset']['column'])) {
+ unset($columns_start['offset']);
+ }
+ else {
+ $columns_start['offset']['length'] = 80;
+ }
+ if ($field['todate']) {
+ if (!db_column_exists($table, $columns_start['offset2']['column'])) {
+ unset($columns_start['offset2']);
+ }
+ else {
+ $columns_start['offset2']['length'] = 80;
+ }
+ }
+ }
+ if (!empty($field['repeat'])) {
+ if (!db_column_exists($table, $columns_start['rrule']['column'])) {
+ unset($columns_start['rrule']);
+ }
+ else {
+ $columns_start['rrule']['length'] = 80;
+ }
+ }
+ $start_field = $field;
+ $start_field['columns'] = $columns_start;
+ $end_field = $field;
+ $end_field['columns'] = $columns_end;
+ content_alter_db($start_field, $end_field);
+ $message = 'Date database integrity check. Updated table '. $table .' to set all columns to accept NULL values.';
+ $ret[] = array('success' => TRUE, 'query' => $message);
+ }
+ }
+ content_clear_type_cache();
+ return $ret;
+}
+
diff --git a/sites/all/modules/date/date/date.module b/sites/all/modules/date/date/date.module
new file mode 100644
index 0000000..456ff0b
--- /dev/null
+++ b/sites/all/modules/date/date/date.module
@@ -0,0 +1,887 @@
+ 'Repeats',
+ 'page callback' => 'date_repeat_page',
+ 'page arguments' => array(1),
+ 'access callback' => 'date_repeat_node',
+ 'access arguments' => array(1),
+ 'type' => MENU_LOCAL_TASK,
+ );
+
+ return $items;
+}
+
+function date_perm() {
+ return array('view date repeats');
+}
+
+function date_repeat_node($node) {
+ if (date_repeat_type($node->type)) {
+ return user_access('view date repeats');
+ }
+ return FALSE;
+}
+
+function date_repeat_type($type_name) {
+ $type = content_types($type_name);
+ if (!empty($type['fields'])) {
+ foreach ($type['fields'] as $field_name => $field) {
+ if (in_array($field['type'], array('date', 'datestamp', 'datetime')) && $field['repeat']) {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+function date_repeat_fields($type_name) {
+ $type = content_types($type_name);
+ $fields = array();
+ if (!empty($type['fields'])) {
+ foreach ($type['fields'] as $field_name => $field) {
+ if (in_array($field['type'], array('date', 'datestamp', 'datetime')) && $field['repeat']) {
+ $fields[] = $field_name;
+ }
+ }
+ }
+ return $fields;
+}
+
+function date_repeat_page($node) {
+ drupal_set_title(check_plain($node->title));
+ $node->date_repeat_show_all = TRUE;
+ $node->build_mode = NODE_BUILD_NORMAL;
+ $node->content = array();
+ $field_names = date_repeat_fields($node->type);
+ $view = content_view($node, FALSE, TRUE);
+ $output = '';
+ foreach ($field_names as $field_name) {
+ $output .= drupal_render($node->content[$field_name]);
+ }
+ return $output;
+}
+
+function date_is_repeat_field($field) {
+ $repeat_widgets = array(
+ 'date_select_repeat',
+ 'date_text_repeat',
+ 'date_popup_repeat',
+ );
+ if (in_array($field['widget']['type'], $repeat_widgets)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Implementation of hook_content_is_empty().
+ */
+function date_content_is_empty($item, $field) {
+ if (empty($item['value'])) {
+ return TRUE;
+ }
+ elseif ($field['todate'] == 'required' && empty($item['value2'])) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Implementation of hook_field_info().
+ */
+function date_field_info() {
+ return array(
+ 'date' => array(
+ 'label' => 'Date',
+ 'description' => t('Store a date in the database as an ISO date, recommended for historical or partial dates.'),
+ ),
+ 'datestamp' => array(
+ 'label' => 'Datestamp',
+ 'description' => t('Store a date in the database as a timestamp, deprecated format to suppport legacy data.'),
+ ),
+ 'datetime' => array(
+ 'label' => 'Datetime',
+ 'description' => t('Store a date in the database as a datetime field, recommended for complete dates and times that may need timezone conversion.'),
+ ),
+ );
+}
+
+/**
+ * Implementation of hook_widget_info().
+ */
+function date_widget_info() {
+ $info = array(
+ 'date_select' => array(
+ 'label' => t('Select List'),
+ 'field types' => array('date', 'datestamp', 'datetime'),
+ 'multiple values' => CONTENT_HANDLE_CORE,
+ 'callbacks' => array(
+ 'default value' => CONTENT_CALLBACK_CUSTOM,
+ ),
+ ),
+ 'date_select_repeat' => array(
+ 'label' => t('Select List with Repeat options'),
+ 'field types' => array('date', 'datestamp', 'datetime'),
+ 'multiple values' => CONTENT_HANDLE_MODULE,
+ 'callbacks' => array(
+ 'default value' => CONTENT_CALLBACK_CUSTOM,
+ ),
+ ),
+ 'date_text' => array(
+ 'label' => t('Text Field with custom input format'),
+ 'field types' => array('date', 'datestamp', 'datetime'),
+ 'multiple values' => CONTENT_HANDLE_CORE,
+ 'callbacks' => array(
+ 'default value' => CONTENT_CALLBACK_CUSTOM,
+ ),
+ ),
+ 'date_text_repeat' => array(
+ 'label' => t('Text Field with Repeat options'),
+ 'field types' => array('date', 'datestamp', 'datetime'),
+ 'multiple values' => CONTENT_HANDLE_MODULE,
+ 'callbacks' => array(
+ 'default value' => CONTENT_CALLBACK_CUSTOM,
+ ),
+ ),
+ );
+ if (module_exists('date_popup')) {
+ $info['date_popup'] = array(
+ 'label' => t('Text Field with Date Pop-up calendar'),
+ 'field types' => array('date', 'datestamp', 'datetime'),
+ 'multiple values' => CONTENT_HANDLE_CORE,
+ 'callbacks' => array(
+ 'default value' => CONTENT_CALLBACK_CUSTOM,
+ ),
+ );
+ $info['date_popup_repeat'] = array(
+ 'label' => t('Text Field with Date Pop-up and Repeat options'),
+ 'field types' => array('date', 'datestamp', 'datetime'),
+ 'multiple values' => CONTENT_HANDLE_MODULE,
+ 'callbacks' => array(
+ 'default value' => CONTENT_CALLBACK_CUSTOM,
+ ),
+ );
+ }
+ if (!module_exists('date_repeat')) {
+ unset($info['date_select_repeat']);
+ unset($info['date_text_repeat']);
+ if (isset($info['date_popup_repeat'])) {
+ unset($info['date_popup_repeat']);
+ }
+ }
+ return $info;
+}
+
+function date_default_format($type) {
+ if (stristr($type, 'date_popup') && module_exists('date_popup')) {
+ $formats = date_popup_formats();
+ $default_format = array_shift($formats);
+ }
+ else {
+ // example input formats must show all possible date parts, so add seconds.
+ $default_format = str_replace('i', 'i:s', variable_get('date_format_short', 'm/d/Y - H:i'));
+ }
+ return $default_format;
+}
+
+function date_input_value($field, $element) {
+ switch ($field['widget']['type']) {
+ case 'date_text':
+ case 'date_text_repeat':
+ $function = 'date_text_input_value';
+ break;
+ case 'date_popup':
+ case 'date_popup_repeat':
+ $function = 'date_popup_input_value';
+ break;
+ default:
+ $function = 'date_select_input_value';
+ }
+ return $function($element);
+}
+
+/**
+ * Implementation of hook_field_formatter_info().
+ */
+function date_field_formatter_info() {
+ $formatters = array(
+ 'default' => array('label' => t('Default'),
+ 'field types' => array('date', 'datestamp', 'datetime'),
+ 'multiple values' => CONTENT_HANDLE_CORE),
+ 'format_interval' => array('label' => t('As Time Ago'),
+ 'field types' => array('date', 'datestamp', 'datetime'),
+ 'multiple values' => CONTENT_HANDLE_CORE),
+ );
+
+ $format_types = date_get_format_types('', TRUE);
+ if (!empty($format_types)) {
+ foreach ($format_types as $type => $type_info) {
+ $formatters[$type] = array(
+ 'label' => $type_info['title'],
+ 'field types' => array('date', 'datestamp', 'datetime'),
+ 'multiple values' => CONTENT_HANDLE_CORE,
+ );
+ }
+ }
+
+ return $formatters;
+}
+
+/**
+ * Implementation of hook_theme().
+ */
+function date_theme() {
+ $path = drupal_get_path('module', 'date');
+ require_once "./$path/date.theme";
+
+ $base = array(
+ 'file' => 'date.theme',
+ 'path' => "$path",
+ );
+ $themes = array(
+ 'date_combo' => array(
+ 'arguments' => array('element' => NULL)),
+ 'date_all_day' => array(
+ 'arguments' => array(
+ 'which' => NULL, 'date1' => NULL, 'date2' => NULL,
+ 'format' => NULL, 'node' => NULL, 'view' => NULL)),
+ 'date_all_day_label' => array(
+ 'arguments' => array()),
+ 'date_display_single' => array(
+ 'arguments' => array('date' => NULL, 'timezone' => NULL)),
+ 'date_display_range' => array(
+ 'arguments' => array('date1' => NULL, 'date2' => NULL, 'timezone' => NULL)),
+ 'date_text_parts' => array(
+ 'arguments' => array('element' => NULL)),
+ 'date' => array(
+ 'arguments' => array('element' => NULL)),
+ 'date_formatter_default' => $base + array(
+ 'arguments' => array('element' => NULL),
+ 'function' => 'theme_date_display_combination'),
+ 'date_formatter_format_interval' => $base + array(
+ 'arguments' => array('element' => NULL),
+ 'function' => 'theme_date_format_interval'),
+ 'date_formatter_format_calendar_day' => $base + array(
+ 'arguments' => array('element' => NULL),
+ 'function' => 'theme_date_format_calendar_day'),
+ 'date_repeat_display' => $base + array(
+ 'arguments' => array('field' => NULL,
+ 'item' => NULL, 'node' => NULL, 'dates' => NULL),
+ 'function' => 'theme_date_repeat_display',
+ ),
+ );
+
+ // Table isn't available first time date_theme() is called in update.php.
+ if (db_table_exists('date_format_types')) {
+ $format_types = date_get_format_types('', TRUE);
+ if (!empty($format_types)) {
+ foreach ($format_types as $type => $type_info) {
+ $themes['date_formatter_' . $type] = $base + array(
+ 'arguments' => array('element' => NULL),
+ 'function' => 'theme_date_display_combination',
+ );
+ }
+ }
+ }
+
+ return $themes;
+}
+
+/**
+ * Helper function for creating formatted date arrays from a formatter.
+ *
+ * Use the Date API to get an object representation of a date field
+ *
+ * @param array $field
+ * @param array $item - a node field item, like $node->myfield[0]
+ *
+ * @return array that holds the From and To date objects
+ * Each date object looks like:
+ * date [value] => array(
+ * [db] => array( // the value stored in the database
+ * [object] => the datetime object
+ * [datetime] => 2007-02-15 20:00:00
+ * )
+ * [local] => array( // the local representation of that value
+ * [object] => the datetime object
+ * [datetime] => 2007-02-15 14:00:00
+ * [timezone] => US/Central
+ * [offset] => -21600
+ * )
+ * )
+ */
+function date_formatter_process($element) {
+ $node = $element['#node'];
+ $dates = array();
+ $timezone = date_default_timezone_name();
+ if (empty($timezone)) {
+ return $dates;
+ }
+ $field_name = $element['#field_name'];
+ $fields = content_fields();
+ $field = $fields[$field_name];
+ $formatter = $element['#formatter'];
+ $format = date_formatter_format($formatter, $field_name);
+ $item = $element['#item'];
+ $timezone = isset($item['timezone']) ? $item['timezone'] : '';
+ $timezone = date_get_timezone($field['tz_handling'], $timezone);
+ $timezone_db = date_get_timezone_db($field['tz_handling']);
+ $process = date_process_values($field);
+ foreach ($process as $processed) {
+ if (empty($item[$processed])) {
+ $dates[$processed] = NULL;
+ }
+ else {
+ // create a date object with a gmt timezone from the database value
+ $value = $item[$processed];
+ if ($field['type'] == DATE_ISO) {
+ $value = str_replace(' ', 'T', date_fuzzy_datetime($value));
+ }
+ $date = date_make_date($value, $timezone_db, $field['type'], $field['granularity']);
+ $dates[$processed] = array();
+ $dates[$processed]['db']['object'] = $date;
+ $dates[$processed]['db']['datetime'] = date_format($date, DATE_FORMAT_DATETIME);
+
+ date_timezone_set($date, timezone_open($timezone));
+ $dates[$processed]['local']['object'] = $date;
+ $dates[$processed]['local']['datetime'] = date_format($date, DATE_FORMAT_DATETIME);
+ $dates[$processed]['local']['timezone'] = $timezone;
+ $dates[$processed]['local']['offset'] = date_offset_get($date);
+
+ //format the date, special casing the 'interval' format which doesn't need to be processed
+ $dates[$processed]['formatted'] = '';
+ if (is_object($date)) {
+ if ($format == 'format_interval') {
+ $dates[$processed]['interval'] = date_format_interval($date);
+ }
+ elseif ($format == 'format_calendar_day') {
+ $dates[$processed]['calendar_day'] = date_format_calendar_day($date);
+ }
+ elseif ($format == 'U') {
+ $dates[$processed]['formatted'] = date_format_date($date, 'custom', $format);
+ $dates[$processed]['formatted_date'] = date_format_date($date, 'custom', $format);
+ $dates[$processed]['formatted_time'] = '';
+ $dates[$processed]['formatted_timezone'] = '';
+ }
+ elseif (!empty($format)) {
+ $dates[$processed]['formatted'] = date_format_date($date, 'custom', $format);
+ $dates[$processed]['formatted_date'] = date_format_date($date, 'custom', date_limit_format($format, array('year', 'month', 'day')));
+ $dates[$processed]['formatted_time'] = date_format_date($date, 'custom', date_limit_format($format, array('hour', 'minute', 'second')));
+ $dates[$processed]['formatted_timezone'] = date_format_date($date, 'custom', date_limit_format($format, array('timezone')));
+ }
+ }
+ }
+ }
+ if (empty($dates['value2'])) {
+ $dates['value2'] = $dates['value'];
+ }
+ $date1 = $dates['value']['local']['object'];
+ $date2 = $dates['value2']['local']['object'];
+
+ $all_day = '';
+ $all_day2 = '';
+ if ($format != 'format_interval') {
+ $all_day1 = theme('date_all_day', $field, 'date1', $date1, $date2, $format, $node);
+ $all_day2 = theme('date_all_day', $field, 'date2', $date1, $date2, $format, $node);
+ }
+ if ((!empty($all_day1) && $all_day1 != $dates['value']['formatted'])
+ || (!empty($all_day2) && $all_day2 != $dates['value2']['formatted'])) {
+ $dates['value']['formatted_time'] = theme('date_all_day_label');
+ $dates['value2']['formatted_time'] = theme('date_all_day_label');
+ $dates['value']['formatted'] = $all_day1;
+ $dates['value2']['formatted'] = $all_day2;
+ }
+ $dates['format'] = $format;
+ return $dates;
+}
+
+/**
+ * $field['granularity'] will contain an array like ('hour' => 'hour', 'month' => 0)
+ * where the values turned on return their own names and the values turned off return a zero
+ * need to reconfigure this into a simple array of the turned on values
+ */
+function date_granularity($field) {
+ if (!is_array($field) || !is_array($field['granularity'])) {
+ $field['granularity'] = drupal_map_assoc(array('year', 'month', 'day'));
+ }
+ return array_values(array_filter($field['granularity']));
+}
+
+/**
+ * Helper function to create an array of the date values in a
+ * field that need to be processed.
+ */
+function date_process_values($field) {
+ return $field['todate'] ? array('value', 'value2') : array('value');
+}
+
+/**
+ * Implementation of hook_help().
+ */
+function date_help($path, $arg) {
+ switch ($path) {
+ case 'admin/help#date':
+ return '
' . t('Complete documentation for the Date and Date API modules is available at http://drupal.org/node/92460.', array('@link' => 'http://drupal.org/node/92460')) . '
';
+ break;
+ }
+}
+
+/**
+ * Implementation of hook_form_alter().
+ * Make sure date information gets updated.
+ */
+function date_form_alter(&$form, &$form_state, $form_id) {
+ if ($form_id == 'content_display_overview_form') {
+ date_content_display_form($form, $form_state);
+ }
+}
+
+/**
+ * Implementation of hook_field().
+ *
+ * Validation and submission operation code is moved into a separate
+ * file and included only when processing forms.
+ */
+function date_field($op, &$node, $field, &$items, $teaser, $page) {
+ // Add some information needed to interpret token values.
+ $additions[$field['field_name']] = $items;
+ foreach ($items as $delta => $item) {
+ $timezone = isset($item['timezone']) ? $item['timezone'] : '';
+ if (is_array($additions[$field['field_name']][$delta])) {
+ $additions[$field['field_name']][$delta]['timezone'] = date_get_timezone($field['tz_handling'], $timezone);
+ $additions[$field['field_name']][$delta]['timezone_db'] = date_get_timezone_db($field['tz_handling']);
+ $additions[$field['field_name']][$delta]['date_type'] = $field['type'];
+ }
+ }
+ switch ($op) {
+ case 'load':
+ return $additions;
+ break;
+ case 'validate':
+ require_once('./'. drupal_get_path('module', 'date') .'/date_elements.inc');
+ return _date_field_validate($op, $node, $field, $items, $teaser, $page);
+ break;
+ case 'presave':
+ case 'insert':
+ case 'update':
+ require_once('./'. drupal_get_path('module', 'date') .'/date_elements.inc');
+ $items = $additions[$field['field_name']];
+ if ($additions[$field['field_name']]) {
+ $node->$field['field_name'] = $additions;
+ }
+ return _date_field_update($op, $node, $field, $items, $teaser, $page);
+ break;
+ case 'sanitize':
+ //foreach ($items as $delta => $item) {
+ //$dates = date_formatter_process($field, $item, $node, $formatter);
+ //$node->$field['field_name'][$delta]['dates'] = $dates;
+ //}
+ }
+}
+
+/**
+ * Implementation of hook_widget().
+ *
+ * This code and all the processes it uses are in a separate file,
+ * included only when processing forms.
+ */
+function date_widget(&$form, &$form_state, &$field, $items, $delta) {
+ require_once('./'. drupal_get_path('module', 'date') .'/date_elements.inc');
+ return _date_widget($form, $form_state, $field, $items, $delta);
+}
+
+/**
+ * Implementation of hook_elements().
+ *
+ * This code and all the processes it uses are in a separate file,
+ * included only when processing forms.
+ */
+function date_elements() {
+ require_once('./'. drupal_get_path('module', 'date') .'/date_elements.inc');
+ return _date_elements();
+}
+
+/**
+ * Implementation of Devel module's hook_content_generate().
+ */
+function date_content_generate($node, $field) {
+ require_once('./'. drupal_get_path('module', 'date') .'/date_content_generate.inc');
+ return _date_content_generate($node, $field);
+}
+
+/**
+ * Wrapper functions for date administration, included only when
+ * processing field settings.
+ */
+function date_widget_settings($op, $widget) {
+ require_once('./'. drupal_get_path('module', 'date') .'/date_admin.inc');
+ return _date_widget_settings($op, $widget);
+}
+
+function date_field_settings($op, $field) {
+ require_once('./'. drupal_get_path('module', 'date') .'/date_admin.inc');
+ return _date_field_settings($op, $field);
+}
+
+function date_formatter_settings($form_state = NULL, $field, $options = array(), $views_form = FALSE) {
+ require_once('./'. drupal_get_path('module', 'date') .'/date_admin.inc');
+ return _date_formatter_settings($form_state, $field, $options, $views_form);
+}
+
+/**
+ * Helper function to return the date format used by a specific formatter.
+ */
+function date_formatter_format($formatter, $field_name) {
+ $fields = content_fields();
+ $field = $fields[$field_name];
+ $default = variable_get('date_format_medium', 'D, m/d/Y - H:i');
+ switch ($formatter) {
+ case 'format_interval':
+ return 'format_interval';
+ case 'default':
+ $format = variable_get('date_format_'. $field['default_format'], $default);
+ break;
+ default:
+ $format = variable_get('date_format_'. $formatter, $default);
+ break;
+ }
+
+ if (empty($format)) {
+ $format = $default;
+ }
+ // A selected format might include timezone information.
+ $granularity = date_granularity($field);
+ array_push($granularity, 'timezone');
+ return date_limit_format($format, $granularity);
+}
+
+/**
+ * Implementation of hook_views_api().
+ */
+function date_views_api() {
+ return array(
+ 'api' => 2,
+ 'path' => drupal_get_path('module', 'date'),
+ );
+}
+
+/**
+ * Helper function to adapt node date fields to formatter settings.
+ */
+function date_prepare_node($node, $field, $type_name, $context, $options) {
+
+ // If there are options to limit multiple values,
+ // alter the node values to match.
+ $field_name = $field['field_name'];
+
+ $max_count = $options['multiple']['multiple_number'];
+
+ // If no results should be shown, empty the values and return.
+ if (is_numeric($max_count) && $max_count == 0) {
+ $node->{$field_name} = array();
+ return $node;
+ }
+
+ // Otherwise removed values that should not be displayed.
+ if (!empty($options['multiple']['multiple_from']) || !empty($options['multiple']['multiple_to']) || !empty($max_count)) {
+ $format = date_type_format($field['type']);
+ include_once(drupal_get_path('module', 'date_api') .'/date_api_sql.inc');
+ $date_handler = new date_sql_handler($field);
+ $arg0 = !empty($options['multiple']['multiple_from']) ? date_format(date_create($options['multiple']['multiple_from'], date_default_timezone()), DATE_FORMAT_DATETIME) : variable_get('date_min_year', 100) .'-01-01T00:00:00';
+ $arg1 = !empty($options['multiple']['multiple_to']) ? date_format(date_create($options['multiple']['multiple_to'], date_default_timezone()), DATE_FORMAT_DATETIME) : variable_get('date_max_year', 4000) .'-12-31T23:59:59';
+
+ if (!empty($arg0) && !empty($arg1)) {
+ $arg = $arg0 .'--'. $arg1;
+ }
+ elseif (!empty($arg0)) {
+ $arg = $arg0;
+ }
+ elseif (!empty($arg1)) {
+ $arg = $arg1;
+ }
+ if (!empty($arg)) {
+ $range = $date_handler->arg_range($arg);
+ $start = date_format($range[0], $format);
+ $end = date_format($range[1], $format);
+ // Empty out values we don't want to see.
+ $count = 0;
+ foreach ($node->$field_name as $delta => $value) {
+ if (!empty($node->date_repeat_show_all)) {
+ break;
+ }
+ elseif ((!empty($max_count) && is_numeric($max_count) && $count >= $max_count) ||
+ (!empty($value['value']) && $value['value'] < $start) ||
+ (!empty($value['value2']) && $value['value2'] > $end)) {
+ unset($node->{$field_name}[$delta]);
+ }
+ else {
+ $count++;
+ }
+ }
+ }
+ }
+ return $node;
+}
+
+/**
+ * Identify all fields in this view that use the CCK Date handler.
+ */
+function date_handler_fields($view) {
+ $field_names = array();
+ if (empty($view->date_info->date_fields)) {
+ if (empty($view->date_info)) {
+ $view->date_info = new stdClass;
+ }
+ $view->date_info->date_fields = array();
+ }
+ foreach ($view->field as $field) {
+ if ($field->definition['handler'] == 'date_handler_field_multiple') {
+ $name = $field->field;
+ $group = $field->options['multiple'];
+ if (drupal_substr($name, -7) == '_value2') {
+ $field_name = drupal_substr($name, 0, strlen($name) - 7);
+ }
+ elseif (drupal_substr($name, -6) == '_value') {
+ $field_name = drupal_substr($name, 0, strlen($name) - 6);
+ }
+ else {
+ $field_name = '';
+ $group = array();
+ continue;
+ }
+ foreach ($view->date_info->date_fields as $date_field) {
+ if (strstr($date_field, '.'. $field_name)) {
+ $delta_field = 'node_data_'. $field_name .'_delta';
+ $field_names[$field_name] = array('options' => $group, 'delta_field' => $delta_field, 'view_field' => drupal_clone($field));
+ // Get rid of the huge view object in the field handler.
+ unset($field_names[$field_name]['view_field']->view);
+ }
+ }
+ }
+ }
+ return $field_names;
+}
+
+/**
+ * Generate a DateAPI SQL handler for the given CCK date field.
+ *
+ * The handler will be set up to make the correct timezone adjustments
+ * for the field settings.
+ *
+ * @param $field
+ * - a $field array.
+ * @param $compare_tz
+ * - the timezone used for comparison values in the SQL.
+ */
+ function date_field_get_sql_handler($field, $compare_tz = NULL) {
+ module_load_include('inc', 'date_api', 'date_api_sql');
+
+ $db_info = content_database_info($field);
+
+ // Create a DateAPI SQL handler class for this field type.
+ $handler = new date_sql_handler();
+ $handler->construct($field['type']);
+
+ // If this date field stores a timezone in the DB, tell the handler about it.
+ if ($field['tz_handling'] == 'date') {
+ $handler->db_timezone_field = $db_info['columns']['timezone']['column'];
+ }
+ else {
+ $handler->db_timezone = date_get_timezone_db($field['tz_handling']);
+ }
+
+ if (empty($compare_tz)) {
+ $compare_tz = date_get_timezone($field['tz_handling']);
+ }
+ $handler->local_timezone = $compare_tz;
+
+ // Now that the handler is properly initialized, force the DB
+ // to use UTC so no timezone conversions get added to things like
+ // NOW() or FROM_UNIXTIME().
+ $handler->set_db_timezone();
+
+ return $handler;
+}
+
+/**
+ * Implementation of hook_form_alter().
+ *
+ * Adding ability to configure new date format types.
+ */
+function date_form_date_api_date_formats_form_alter(&$form, $form_state, $form_id = 'date_api_date_formats_form') {
+ // Add form entry field for adding new format type.
+ $form['add_format_type'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Add format type'),
+ '#weight' => 1,
+ );
+ $form['add_format_type']['add_date_format_title'] = array(
+ '#title' => t('Name'),
+ '#description' => t('The human-readable name for this format type.'),
+ '#type' => 'textfield',
+ '#size' => 20,
+ '#prefix' => '
',
+ '#suffix' => '
',
+ );
+ $form['add_format_type']['add_date_format_type'] = array(
+ '#title' => t('Type'),
+ '#description' => t('The machine-readable name of this format type. This name must contain only lowercase letters, numbers, and underscores and must be unique.'),
+ '#type' => 'textfield',
+ '#size' => 20,
+ '#prefix' => '
',
+ '#suffix' => '
',
+ );
+
+ $form['#submit'][] = 'date_date_time_settings_submit';
+ $form['#validate'][] = 'date_date_time_settings_validate';
+ $form['buttons']['#weight'] = 5;
+}
+
+/**
+ * Validate new date format type details.
+ */
+function date_date_time_settings_validate($form, &$form_state) {
+ if (!empty($form_state['values']['add_date_format_type']) && !empty($form_state['values']['add_date_format_title'])) {
+ if (!preg_match("/^[a-zA-Z0-9_]+$/", $form_state['values']['add_date_format_type'])) {
+ form_set_error('add_date_format_type', t('The format type must contain only alphanumeric characters and underscores.'));
+ }
+ $types = date_get_format_types();
+ if (in_array($form_state['values']['add_date_format_type'], array_keys($types))) {
+ form_set_error('add_date_format_type', t('This format type already exists. Please enter a unique type.'));
+ }
+ }
+}
+
+/**
+ * Save date format type to database.
+ */
+function date_date_time_settings_submit($form, &$form_state) {
+ if (!empty($form_state['values']['add_date_format_type']) && !empty($form_state['values']['add_date_format_title'])) {
+ $format_type = array();
+ $format_type['title'] = $form_state['values']['add_date_format_title'];
+ $format_type['type'] = $form_state['values']['add_date_format_type'];
+ $format_type['locked'] = 0;
+ $format_type['is_new'] = 1;
+ date_format_type_save($format_type);
+ }
+
+ // Unset, to prevent this getting saved as a variables.
+ unset($form_state['values']['add_date_format_type']);
+ unset($form_state['values']['add_date_format_title']);
+}
+
+/**
+ * Insert Date field formatter settings into the Display Fields form.
+ */
+function date_content_display_form(&$form, &$form_state) {
+ $fields = content_fields();
+ $date_fields = array();
+ foreach ($fields as $field) {
+ if (in_array($field['type'], array('date', 'datestamp', 'datetime'))) {
+ $date_fields[$field['field_name']] = $field;
+ }
+ }
+ foreach ($form as $field_name => $element) {
+ if (drupal_substr($field_name, 0, 6) == 'field_') {
+ if (array_key_exists($field_name, $date_fields)) {
+ $field = $date_fields[$field_name];
+ foreach ($element as $context => $value) {
+ if (!in_array($context, array('human_name', 'weight', 'parent', 'label'))) {
+ $options['type_name'] = $form['#type_name'];
+ $options['context'] = $context;
+ $base_form = $form[$field_name][$context]['format'];
+ $form[$field_name][$context]['format'] = array();
+ $form[$field_name][$context]['format']['base'] = $base_form;
+ $form[$field_name][$context]['format']['extra'] = date_formatter_settings($form_state, $field, $options);
+ $form[$field_name][$context]['format']['#element_validate'] = array('date_formatter_settings_validate');
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Store the formatter settings
+ * and reset the form back to the value CCK expects.
+ */
+function date_formatter_settings_validate(&$form, &$form_state) {
+ $field = $form['extra']['field']['#value'];
+ $field_name = $field['field_name'];
+
+ $type_name = $form['extra']['type_name']['#value'];
+ $context = $form['extra']['context']['#value'];
+ $form_values = $form_state['values'][$field_name][$context]['format']['extra'];
+ $value = 'date:'. $type_name .':'. $context .':'. $field_name;
+ variable_set($value .'_show_repeat_rule', $form_values['repeat']['show_repeat_rule']);
+ variable_set($value .'_multiple_number', $form_values['multiple']['multiple_number']);
+ variable_set($value .'_multiple_from', $form_values['multiple']['multiple_from']);
+ variable_set($value .'_multiple_to', $form_values['multiple']['multiple_to']);
+ variable_set($value .'_fromto', $form_values['fromto']['fromto']);
+
+ form_set_value($form, $form_state['values'][$field_name][$context]['format']['base'], $form_state);
+}
+
+function date_formatter_get_settings($field_name, $type_name, $context) {
+ $options = array();
+ $value = 'date:'. $type_name .':'. $context .':'. $field_name;
+ $options['repeat']['show_repeat_rule'] = variable_get($value .'_show_repeat_rule', 'show');
+ $options['multiple']['multiple_number'] = variable_get($value .'_multiple_number', '');
+ $options['multiple']['multiple_from'] = variable_get($value .'_multiple_from', '');
+ $options['multiple']['multiple_to'] = variable_get($value .'_multiple_to', '');
+ $options['fromto']['fromto'] = variable_get($value .'_fromto', 'both');
+ return $options;
+}
+
+/**
+ * Determine if a from/to date combination qualify as 'All day'.
+ *
+ * @param array $field, the field definition for this date field.
+ * @param object $date1, a date/time object for the 'from' date.
+ * @param object $date2, a date/time object for the 'to' date.
+ * @return TRUE or FALSE.
+ */
+function date_field_all_day($field, $date1, $date2 = NULL) {
+ if (empty($date1) || !is_object($date1)) {
+ return FALSE;
+ }
+ elseif (!date_has_time($field['granularity'])) {
+ return TRUE;
+ }
+ if (empty($date2)) {
+ $date2 = $date1;
+ }
+ $granularity = date_granularity_precision($field['granularity']);
+ $increment = isset($field['widget']['increment']) ? $field['widget']['increment'] : 1;
+ $date1 = date_format($date1, DATE_FORMAT_DATETIME);
+ $date2 = date_format($date2, DATE_FORMAT_DATETIME);
+ return date_is_all_day($date1, $date2, $granularity, $increment);
+
+}
+
diff --git a/sites/all/modules/date/date/date.theme b/sites/all/modules/date/date/date.theme
new file mode 100644
index 0000000..0eed06b
--- /dev/null
+++ b/sites/all/modules/date/date/date.theme
@@ -0,0 +1,283 @@
+date_id
+ * If set, this will show only an individual date on a field with
+ * multiple dates. The value should be a string that contains
+ * the following values, separated with periods:
+ * - module name of the module adding the item
+ * - node nid
+ * - field name
+ * - delta value of the field to be displayed
+ * - other information the module's custom theme might need
+ *
+ * Used by the calendar module and available for other uses.
+ * example: 'date.217.field_date.3.test'
+ *
+ * $node->date_repeat_show
+ * If true, tells the theme to show all the computed values
+ * of a repeating date. If not true or not set, only the
+ * start date and the repeat rule will be displayed.
+ *
+ * $dates['format'] - the format string used on these dates
+ * $dates['value']['local']['object'] - the local date object for the From date
+ * $dates['value2']['local']['object'] - the local date object for the To date
+ * $dates['value']['local']['datetime'] - the datetime value of the From date database (GMT) value
+ * $dates['value2']['local']['datetime'] - the datetime value of the To date database (GMT) value
+ * $dates['value']['formatted'] = formatted From date, i.e. 'February 15, 2007 2:00 pm';
+ * $dates['value']['formatted_date'] - only the date part of the formatted From date
+ * $dates['value']['formatted_time'] - only the time part of the formatted From date
+ * $dates['value2']['formatted'] = formatted To date, i.e. 'February 15, 2007 6:00 pm';
+ * $dates['value2']['formatted_date'] - only the date part of the formatted To date
+ * $dates['value2']['formatted_time'] - only the time part of the formatted To date
+ */
+function theme_date_display_combination($element) {
+ static $repeating_ids = array();
+
+ $node = $element['#node'];
+ $field_name = $element['#field_name'];
+ $context = !empty($node->content) && !empty($node->content[$field_name]) ? $node->content[$field_name]['#context'] : 'full';
+ $type_name = $element['#type_name'];
+ $fields = content_fields();
+ $field = $fields[$field_name];
+ $item = $element['#item'];
+
+ // Get the formatter settings, either the default settings for this node
+ // type or the View settings stored in $node->date_info.
+ $options = date_formatter_get_settings($field_name, $type_name, $context);
+ if (!empty($node->date_info) && !empty($node->date_info->formatter_settings)) {
+ $options = $node->date_info->formatter_settings;
+ }
+
+ $output = '';
+
+ // If date_id is set for this field and the delta doesn't match, don't display it.
+ if (!empty($node->date_id)) {
+ foreach ((array) $node->date_id as $key => $id) {
+ list($module, $nid, $field_name, $delta, $other) = explode('.', $id);
+ if ($field_name == $field['field_name'] && isset($item['#delta']) && $delta != $item['#delta']) {
+ return $output;
+ }
+ }
+ }
+
+ // Check the formatter settings to see if the repeat rule should be
+ // displayed. Show it only with the first multiple value date.
+ if (!in_array($node->nid, $repeating_ids) && module_exists('date_repeat')
+ && !empty($item['rrule']) && $options['repeat']['show_repeat_rule'] == 'show') {
+ require_once('./'. drupal_get_path('module', 'date') .'/date_repeat.inc');
+ $output .= theme('date_repeat_display', $field, $item, $node);
+ $repeating_ids[] = $node->nid;
+ }
+
+ // If this is a full node or a pseudo node created by grouping
+ // multiple values, see exactly which values are supposed to be visible.
+ if (isset($node->$field_name)) {
+ $node = date_prepare_node($node, $field, $type_name, $context, $options);
+ // Did the current value get removed by formatter settings?
+ if (empty($node->{$field_name}[$item['#delta']])) {
+ return $output;
+ }
+ // Adjust the $element values to match the changes.
+ $element['#node'] = $node;
+ }
+
+ // Call the right theme for this formatter.
+ // Update the element with values that might have been altered by
+ // date_prepare_node() and figure out which values to display.
+ $dates = date_formatter_process($element);
+ switch ($options['fromto']['fromto']) {
+ case 'value':
+ $date1 = $dates['value']['formatted'];
+ $date2 = $date1;
+ break;
+ case 'value2':
+ $date2 = $dates['value2']['formatted'];
+ $date1 = $date2;
+ break;
+ default:
+ $date1 = $dates['value']['formatted'];
+ $date2 = $dates['value2']['formatted'];
+ break;
+ }
+
+ // Pull the timezone, if any, out of the formatted result and tack it
+ // back on at the end, if it is in the current formatted date.
+ $timezone = $dates['value']['formatted_timezone'];
+ if ($timezone) {
+ $timezone = ' ' . $timezone;
+ }
+ $date1 = str_replace($timezone, '', $date1);
+ $date2 = str_replace($timezone, '', $date2);
+
+ // No date values, display nothing.
+ if (empty($date1) && empty($date2)) {
+ $output .= '';
+ }
+ // From and To dates match or there is no To date, display a complete single date.
+ elseif ($date1 == $date2 || empty($date2)) {
+ $output .= theme('date_display_single', $date1, $timezone);
+ }
+ // Same day, different times, don't repeat the date but show both From and To times.
+ elseif (date_has_time($field['granularity']) && $dates['value']['formatted_date'] == $dates['value2']['formatted_date']) {
+ // Replace the original time with the from/to time in the formatted start date.
+ // Make sure that parentheses or brackets wrapping the time will be retained in the
+ // final result.
+ $time1 = preg_replace('`^([\(\[])`', '', $dates['value']['formatted_time']);
+ $time1 = preg_replace('([\)\]]$)', '', $time1);
+ $time2 = preg_replace('`^([\(\[])`', '', $dates['value2']['formatted_time']);
+ $time2 = preg_replace('([\)\]]$)', '', $time2);
+ $time = theme('date_display_range', $time1, $time2);
+ $replaced = str_replace($time1, $time, $date1);
+ $output .= theme('date_display_single', $replaced, $timezone);
+ }
+ // Different days, display both in their entirety.
+ else {
+ $output .= theme('date_display_range', $date1, $date2, $timezone);
+ }
+ return $output;
+}
+
+function theme_date_display_single($date, $timezone = NULL) {
+ return ''. $date . $timezone .'';
+}
+
+function theme_date_display_range($date1, $date2, $timezone = NULL) {
+ return ''. $date1 .''.
+ ' - ' .
+ ''. $date2 . $timezone. '';
+}
+
+/**
+ * Theme a format interval for a date element
+ *
+ * @param $field = the field settings
+ * @param $node = node information, this is not always available and not
+ * always the full node, it depends on what value was provided to the formatter.
+ * Only the nid is always guaranteed to be available.
+ * @param $dates - an array of date information, see explanation for date_field_object for details.
+ * @return a formatted display
+ *
+ */
+function theme_date_format_interval($element) {
+ $node = $element['#node'];
+ $field_name = $element['#field_name'];
+ $context = !empty($node->content) ? $node->content[$field_name]['#context'] : 'full';
+ $type_name = $element['#type_name'];
+ $fields = content_fields();
+ $field = $fields[$field_name];
+ $item = $element['#item'];
+
+ // Get the formatter settings, either the default settings for this node
+ // type or the View settings stored in $node->date_info.
+ $options = date_formatter_get_settings($field_name, $type_name, $context);
+ if (!empty($node->date_info) && !empty($node->date_info->formatter_settings)) {
+ $options = $node->date_info->formatter_settings;
+ }
+
+ // If date_id is set for this field and the delta doesn't match, don't display it.
+ if (!empty($node->date_id)) {
+ foreach ((array) $node->date_id as $key => $id) {
+ list($module, $nid, $field_name, $delta, $other) = explode('.', $id);
+ if ($field_name == $field['field_name'] && isset($item['#delta']) && $delta != $item['#delta']) {
+ return;
+ }
+ }
+ }
+
+ // If this is not coming from Views, it is the full node.
+ // If we aren't retrieving a specific value, adjust the node values
+ // to match the formatter settings, removing values we should not see.
+ if (!empty($node->content) && empty($node->date_id)) {
+ $node = date_prepare_node($node, $field, $type_name, $context, $options);
+
+ // Did the current value get removed by formatter settings?
+ if (empty($node->{$field_name}[$item['#delta']])) {
+ return;
+ }
+ // Adjust the $element values to match the changes.
+ $element['#node'] = $node;
+ }
+ $dates = date_formatter_process($element);
+ return theme('date_time_ago', $dates['value']['local']['object'], $dates['value2']['local']['object']);
+}
+
+/**
+ * Theme the human-readable description for a Date Repeat rule.
+ *
+ * TODO -
+ * add in ways to store the description in the date so it isn't regenerated
+ * over and over and find a way to allow description to be shown or hidden.
+ */
+function theme_date_repeat_display($field, $item, $node = NULL) {
+ $output = '';
+ if (!empty($item['rrule'])) {
+ $output = date_repeat_rrule_description($item['rrule']);
+ $output = '
'. $output .'
';
+ }
+ return $output;
+}
+
+/**
+ * Adjust from/to date format to account for 'all day'.
+ *
+ * @param array $field, the field definition for this date field.
+ * @param string $which, which value to return, 'date1' or 'date2'.
+ * @param object $date1, a date/time object for the 'from' date.
+ * @param object $date2, a date/time object for the 'to' date.
+ * @param string $format
+ * @param object $node, the node this date comes from (may be incomplete, always contains nid).
+ * @param object $view, the view this node comes from, if applicable.
+ * @return formatted date.
+ */
+function theme_date_all_day($field, $which, $date1, $date2, $format, $node, $view = NULL) {
+
+ if (empty($date1) || !is_object($date1) || $format == 'format_interval') {
+ return;
+ }
+ if (empty($date2)) {
+ $date2 = $date1;
+ }
+
+ $suffix = '';
+ if (!date_has_time($field['granularity'])) {
+ $format = date_limit_format($format, array('year', 'month', 'day'));
+ }
+ else {
+ $format_granularity = date_format_order($format);
+ $format_has_time = FALSE;
+ if (in_array('hour', $format_granularity)) {
+ $format_has_time = TRUE;
+ }
+ $all_day = date_field_all_day($field, $date1, $date2);
+ if ($all_day && $format_has_time) {
+ $format = date_limit_format($format, array('year', 'month', 'day'));
+# $suffix = ' ' . theme('date_all_day_label');
+ }
+ }
+
+ return trim(date_format_date($$which, 'custom', $format) . $suffix);
+
+}
+
+/**
+ * Theme the way an 'all day' label will look.
+ */
+function theme_date_all_day_label() {
+# return '('. date_t('All day', 'datetime') .')';
+ return '';
+}
+/** @} End of addtogroup themeable */
diff --git a/sites/all/modules/date/date/date.theme.original b/sites/all/modules/date/date/date.theme.original
new file mode 100644
index 0000000..ddf1742
--- /dev/null
+++ b/sites/all/modules/date/date/date.theme.original
@@ -0,0 +1,282 @@
+date_id
+ * If set, this will show only an individual date on a field with
+ * multiple dates. The value should be a string that contains
+ * the following values, separated with periods:
+ * - module name of the module adding the item
+ * - node nid
+ * - field name
+ * - delta value of the field to be displayed
+ * - other information the module's custom theme might need
+ *
+ * Used by the calendar module and available for other uses.
+ * example: 'date.217.field_date.3.test'
+ *
+ * $node->date_repeat_show
+ * If true, tells the theme to show all the computed values
+ * of a repeating date. If not true or not set, only the
+ * start date and the repeat rule will be displayed.
+ *
+ * $dates['format'] - the format string used on these dates
+ * $dates['value']['local']['object'] - the local date object for the From date
+ * $dates['value2']['local']['object'] - the local date object for the To date
+ * $dates['value']['local']['datetime'] - the datetime value of the From date database (GMT) value
+ * $dates['value2']['local']['datetime'] - the datetime value of the To date database (GMT) value
+ * $dates['value']['formatted'] = formatted From date, i.e. 'February 15, 2007 2:00 pm';
+ * $dates['value']['formatted_date'] - only the date part of the formatted From date
+ * $dates['value']['formatted_time'] - only the time part of the formatted From date
+ * $dates['value2']['formatted'] = formatted To date, i.e. 'February 15, 2007 6:00 pm';
+ * $dates['value2']['formatted_date'] - only the date part of the formatted To date
+ * $dates['value2']['formatted_time'] - only the time part of the formatted To date
+ */
+function theme_date_display_combination($element) {
+ static $repeating_ids = array();
+
+ $node = $element['#node'];
+ $field_name = $element['#field_name'];
+ $context = !empty($node->content) && !empty($node->content[$field_name]) ? $node->content[$field_name]['#context'] : 'full';
+ $type_name = $element['#type_name'];
+ $fields = content_fields();
+ $field = $fields[$field_name];
+ $item = $element['#item'];
+
+ // Get the formatter settings, either the default settings for this node
+ // type or the View settings stored in $node->date_info.
+ $options = date_formatter_get_settings($field_name, $type_name, $context);
+ if (!empty($node->date_info) && !empty($node->date_info->formatter_settings)) {
+ $options = $node->date_info->formatter_settings;
+ }
+
+ $output = '';
+
+ // If date_id is set for this field and the delta doesn't match, don't display it.
+ if (!empty($node->date_id)) {
+ foreach ((array) $node->date_id as $key => $id) {
+ list($module, $nid, $field_name, $delta, $other) = explode('.', $id);
+ if ($field_name == $field['field_name'] && isset($item['#delta']) && $delta != $item['#delta']) {
+ return $output;
+ }
+ }
+ }
+
+ // Check the formatter settings to see if the repeat rule should be
+ // displayed. Show it only with the first multiple value date.
+ if (!in_array($node->nid, $repeating_ids) && module_exists('date_repeat')
+ && !empty($item['rrule']) && $options['repeat']['show_repeat_rule'] == 'show') {
+ require_once('./'. drupal_get_path('module', 'date') .'/date_repeat.inc');
+ $output .= theme('date_repeat_display', $field, $item, $node);
+ $repeating_ids[] = $node->nid;
+ }
+
+ // If this is a full node or a pseudo node created by grouping
+ // multiple values, see exactly which values are supposed to be visible.
+ if (isset($node->$field_name)) {
+ $node = date_prepare_node($node, $field, $type_name, $context, $options);
+ // Did the current value get removed by formatter settings?
+ if (empty($node->{$field_name}[$item['#delta']])) {
+ return $output;
+ }
+ // Adjust the $element values to match the changes.
+ $element['#node'] = $node;
+ }
+
+ // Call the right theme for this formatter.
+ // Update the element with values that might have been altered by
+ // date_prepare_node() and figure out which values to display.
+ $dates = date_formatter_process($element);
+ switch ($options['fromto']['fromto']) {
+ case 'value':
+ $date1 = $dates['value']['formatted'];
+ $date2 = $date1;
+ break;
+ case 'value2':
+ $date2 = $dates['value2']['formatted'];
+ $date1 = $date2;
+ break;
+ default:
+ $date1 = $dates['value']['formatted'];
+ $date2 = $dates['value2']['formatted'];
+ break;
+ }
+
+ // Pull the timezone, if any, out of the formatted result and tack it
+ // back on at the end, if it is in the current formatted date.
+ $timezone = $dates['value']['formatted_timezone'];
+ if ($timezone) {
+ $timezone = ' ' . $timezone;
+ }
+ $date1 = str_replace($timezone, '', $date1);
+ $date2 = str_replace($timezone, '', $date2);
+
+ // No date values, display nothing.
+ if (empty($date1) && empty($date2)) {
+ $output .= '';
+ }
+ // From and To dates match or there is no To date, display a complete single date.
+ elseif ($date1 == $date2 || empty($date2)) {
+ $output .= theme('date_display_single', $date1, $timezone);
+ }
+ // Same day, different times, don't repeat the date but show both From and To times.
+ elseif (date_has_time($field['granularity']) && $dates['value']['formatted_date'] == $dates['value2']['formatted_date']) {
+ // Replace the original time with the from/to time in the formatted start date.
+ // Make sure that parentheses or brackets wrapping the time will be retained in the
+ // final result.
+ $time1 = preg_replace('`^([\(\[])`', '', $dates['value']['formatted_time']);
+ $time1 = preg_replace('([\)\]]$)', '', $time1);
+ $time2 = preg_replace('`^([\(\[])`', '', $dates['value2']['formatted_time']);
+ $time2 = preg_replace('([\)\]]$)', '', $time2);
+ $time = theme('date_display_range', $time1, $time2);
+ $replaced = str_replace($time1, $time, $date1);
+ $output .= theme('date_display_single', $replaced, $timezone);
+ }
+ // Different days, display both in their entirety.
+ else {
+ $output .= theme('date_display_range', $date1, $date2, $timezone);
+ }
+ return $output;
+}
+
+function theme_date_display_single($date, $timezone = NULL) {
+ return ''. $date . $timezone .'';
+}
+
+function theme_date_display_range($date1, $date2, $timezone = NULL) {
+ return ''. $date1 .''.
+ ' - ' .
+ ''. $date2 . $timezone. '';
+}
+
+/**
+ * Theme a format interval for a date element
+ *
+ * @param $field = the field settings
+ * @param $node = node information, this is not always available and not
+ * always the full node, it depends on what value was provided to the formatter.
+ * Only the nid is always guaranteed to be available.
+ * @param $dates - an array of date information, see explanation for date_field_object for details.
+ * @return a formatted display
+ *
+ */
+function theme_date_format_interval($element) {
+ $node = $element['#node'];
+ $field_name = $element['#field_name'];
+ $context = !empty($node->content) ? $node->content[$field_name]['#context'] : 'full';
+ $type_name = $element['#type_name'];
+ $fields = content_fields();
+ $field = $fields[$field_name];
+ $item = $element['#item'];
+
+ // Get the formatter settings, either the default settings for this node
+ // type or the View settings stored in $node->date_info.
+ $options = date_formatter_get_settings($field_name, $type_name, $context);
+ if (!empty($node->date_info) && !empty($node->date_info->formatter_settings)) {
+ $options = $node->date_info->formatter_settings;
+ }
+
+ // If date_id is set for this field and the delta doesn't match, don't display it.
+ if (!empty($node->date_id)) {
+ foreach ((array) $node->date_id as $key => $id) {
+ list($module, $nid, $field_name, $delta, $other) = explode('.', $id);
+ if ($field_name == $field['field_name'] && isset($item['#delta']) && $delta != $item['#delta']) {
+ return;
+ }
+ }
+ }
+
+ // If this is not coming from Views, it is the full node.
+ // If we aren't retrieving a specific value, adjust the node values
+ // to match the formatter settings, removing values we should not see.
+ if (!empty($node->content) && empty($node->date_id)) {
+ $node = date_prepare_node($node, $field, $type_name, $context, $options);
+
+ // Did the current value get removed by formatter settings?
+ if (empty($node->{$field_name}[$item['#delta']])) {
+ return;
+ }
+ // Adjust the $element values to match the changes.
+ $element['#node'] = $node;
+ }
+ $dates = date_formatter_process($element);
+ return theme('date_time_ago', $dates['value']['local']['object'], $dates['value2']['local']['object']);
+}
+
+/**
+ * Theme the human-readable description for a Date Repeat rule.
+ *
+ * TODO -
+ * add in ways to store the description in the date so it isn't regenerated
+ * over and over and find a way to allow description to be shown or hidden.
+ */
+function theme_date_repeat_display($field, $item, $node = NULL) {
+ $output = '';
+ if (!empty($item['rrule'])) {
+ $output = date_repeat_rrule_description($item['rrule']);
+ $output = '
'. $output .'
';
+ }
+ return $output;
+}
+
+/**
+ * Adjust from/to date format to account for 'all day'.
+ *
+ * @param array $field, the field definition for this date field.
+ * @param string $which, which value to return, 'date1' or 'date2'.
+ * @param object $date1, a date/time object for the 'from' date.
+ * @param object $date2, a date/time object for the 'to' date.
+ * @param string $format
+ * @param object $node, the node this date comes from (may be incomplete, always contains nid).
+ * @param object $view, the view this node comes from, if applicable.
+ * @return formatted date.
+ */
+function theme_date_all_day($field, $which, $date1, $date2, $format, $node, $view = NULL) {
+
+ if (empty($date1) || !is_object($date1) || $format == 'format_interval') {
+ return;
+ }
+ if (empty($date2)) {
+ $date2 = $date1;
+ }
+
+ $suffix = '';
+ if (!date_has_time($field['granularity'])) {
+ $format = date_limit_format($format, array('year', 'month', 'day'));
+ }
+ else {
+ $format_granularity = date_format_order($format);
+ $format_has_time = FALSE;
+ if (in_array('hour', $format_granularity)) {
+ $format_has_time = TRUE;
+ }
+ $all_day = date_field_all_day($field, $date1, $date2);
+ if ($all_day && $format_has_time) {
+ $format = date_limit_format($format, array('year', 'month', 'day'));
+ $suffix = ' ' . theme('date_all_day_label');
+ }
+ }
+
+ return trim(date_format_date($$which, 'custom', $format) . $suffix);
+
+}
+
+/**
+ * Theme the way an 'all day' label will look.
+ */
+function theme_date_all_day_label() {
+ return '('. date_t('All day', 'datetime') .')';
+}
+/** @} End of addtogroup themeable */
diff --git a/sites/all/modules/date/date/date.views.inc b/sites/all/modules/date/date/date.views.inc
new file mode 100644
index 0000000..a45de9b
--- /dev/null
+++ b/sites/all/modules/date/date/date.views.inc
@@ -0,0 +1,18 @@
+ array(
+ 'path' => drupal_get_path('module', 'date'),
+ ),
+ // A date-specific handler for grouping multiple values.
+ 'handlers' => array(
+ 'date_handler_field_multiple' => array(
+ 'parent' => 'content_handler_field_multiple',
+ ),
+ ),
+ );
+}
diff --git a/sites/all/modules/date/date/date.views_convert.inc b/sites/all/modules/date/date/date.views_convert.inc
new file mode 100644
index 0000000..2420a72
--- /dev/null
+++ b/sites/all/modules/date/date/date.views_convert.inc
@@ -0,0 +1,87 @@
+get_item($display, 'filter', $id);
+ switch ($date_fields[$field['field']]) {
+ case 'default':
+ $field_name = drupal_substr($field['field'], 0, -14);
+ $item['date_fields'] = array('node_data_'. $field_name .'.'. $field_name .'_value');
+ $item['granularity'] = 'second';
+ break;
+ case 'year':
+ $field_name = drupal_substr($field['field'], 0, -11);
+ $item['date_fields'] = array('node_data_'. $field_name .'.'. $field_name .'_value');
+ $item['granularity'] = 'year';
+ break;
+ case 'month':
+ $field_name = drupal_substr($field['field'], 0, -12);
+ $item['date_fields'] = array('node_data_'. $field_name .'.'. $field_name .'_value');
+ $item['granularity'] = 'month';
+ break;
+ case 'day':
+ $field_name = drupal_substr($field['field'], 0, -10);
+ $item['date_fields'] = array('node_data_'. $field_name .'.'. $field_name .'_value');
+ $item['granularity'] = 'day';
+ break;
+ case 'to|default':
+ $field_name = drupal_substr($field['field'], 0, -17);
+ $item['date_fields'] = array('node_data_'. $field_name .'.'. $field_name .'_value2');
+ $item['granularity'] = 'second';
+ break;
+ case 'to|year':
+ $field_name = drupal_substr($field['field'], 0, -14);
+ $item['date_fields'] = array('node_data_'. $field_name .'.'. $field_name .'_value2');
+ $item['granularity'] = 'year';
+ break;
+ case 'to|month':
+ $field_name = drupal_substr($field['field'], 0, -15);
+ $item['date_fields'] = array('node_data_'. $field_name .'.'. $field_name .'_value2');
+ $item['granularity'] = 'month';
+ break;
+ case 'to|day':
+ $field_name = drupal_substr($field['field'], 0, -13);
+ $item['date_fields'] = array('node_data_'. $field_name .'.'. $field_name .'_value2');
+ $item['granularity'] = 'day';
+ break;
+ }
+ $item['table'] = 'node';
+ $item['field'] = 'date_filter';
+ $item['form_type'] = 'date_text';
+ $item['operator'] = $field['operator'] == '<>' ? '!=' : $field['operator'];
+ if ($field['value'] == 'now' || $field['options'] == 'now') {
+ $item['default_date'] = 'now';
+ }
+ else {
+ $item['value'] = $field['value'];
+ $item['default_date'] = $field['options'];
+ }
+ $view->set_item($display, 'filter', $id, $item);
+ }
+ break;
+ }
+}
diff --git a/sites/all/modules/date/date/date_admin.inc b/sites/all/modules/date/date/date_admin.inc
new file mode 100644
index 0000000..ae2c916
--- /dev/null
+++ b/sites/all/modules/date/date/date_admin.inc
@@ -0,0 +1,717 @@
+ CONTENT_CALLBACK_CUSTOM);
+ case 'form':
+ return date_widget_settings_form($field);
+
+ case 'save':
+ return array('default_value', 'default_value_code', 'default_value2', 'default_value_code2', 'input_format', 'input_format_custom', 'increment', 'text_parts', 'year_range', 'label_position');
+
+ case 'validate':
+ if ($field['default_value'] == 'strtotime') {
+ $is_strtotime = @strtotime($field['default_value_code']);
+ if (!$is_strtotime) {
+ form_set_error('default_value_code', t('The Strtotime default value is invalid.'));
+ }
+ }
+ if ($field['default_value2'] == 'strtotime') {
+ $is_strtotime = @strtotime($field['default_value_code2']);
+ if (!$is_strtotime) {
+ form_set_error('default_value_code2', t('The Strtotime default value for the To Date is invalid.'));
+ }
+ }
+ if (in_array($field['widget']['type'], array('date_select', 'date_popup', 'date_select_repeat', 'date_popup_repeat')) && !date_range_valid($field['year_range'])) {
+ form_set_error('year_range', t('Years back and forward must be in the format -9:+9.'));
+ }
+ break;
+ }
+}
+
+/**
+ * Custom widget settings manipulation.
+ *
+ * CCK widget settings can't use form_set_value(),
+ * so do it in a custom function.
+ */
+function date_widget_settings_validate(&$form, &$form_state) {
+ // TODO Not sure there is any limitation any more in this version. Need to check.
+ if ($form_state['values']['widget_type'] == 'date_popup') {
+ // Only a limited set of formats is available for the Date Popup module
+ if (!empty($form_state['values']['input_format_custom']) || !in_array($form_state['values']['input_format'], date_popup_formats())) {
+ form_set_value($form['input_format_custom'], NULL, $form_state);
+ form_set_value($form['input_format'], DATE_FORMAT_DATETIME, $form_state);
+ }
+ }
+ if (isset($form_state['values']['advanced']['label_position'])) {
+ form_set_value($form['label_position'], $form_state['values']['advanced']['label_position'], $form_state);
+ }
+ // Munge the table display for text parts back into an array of text parts.
+ if (is_array($form_state['values']['advanced']['text_parts'])) {
+ form_set_value($form['text_parts'], array_keys(array_filter($form_state['values']['advanced']['text_parts'])), $form_state);
+ }
+}
+
+function date_widget_settings_form($widget) {
+ $form = array(
+ '#element_validate' => array('date_widget_settings_validate'),
+ );
+ $form['input']['default_value'] = array(
+ '#type' => 'select', '#title' => t('Default value'),
+ '#default_value' => !empty($widget['default_value']) ? $widget['default_value'] : 'blank',
+ '#options' => array('blank' => t('Blank'), 'now' => t('Now'), 'strtotime' => t('Relative')),
+ '#description' => t("A default value to use for this field. If you select 'Relative', add details below."),
+ );
+ $form['input']['default_value2'] = array(
+ '#type' => 'select', '#title' => t('Default value for To date'),
+ '#default_value' => !empty($widget['default_value2']) ? $widget['default_value2'] : 'same',
+ '#options' => array('same' => t('Same as From date'), 'blank' => t('Blank'), 'now' => t('Now'), 'strtotime' => t('Relative')),
+ '#description' => t("A default value to use for this field. If you select 'Relative', add details below."),
+ );
+ $form['input']['default'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Customize Default Value'),
+ '#description' => '
' . t("The custom value for a Relative default should be something that describes a time by reference to the current day using strtotime, like '+90 days' (90 days from the day the field is created) or '+1 Saturday' (the next Saturday). See !strtotime for more details.", array('!strtotime' => l(t('strtotime'), 'http://www.php.net/manual/en/function.strtotime.php'))) . '
',
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ );
+ $form['input']['default']['default_value_code'] = array(
+ '#type' => 'textfield', '#title' => t('Custom value for From date'),
+ '#default_value' => isset($widget['default_value_code']) ? $widget['default_value_code'] : '',
+ );
+
+ $form['input']['default']['default_value_code2'] = array(
+ '#type' => 'textfield', '#title' => t('Custom value for To date'),
+ '#default_value' => !empty($widget['default_value_code2']) ? $widget['default_value_code2'] : '',
+ );
+
+ $options = array();
+ if ($widget['type'] == 'date_popup' && module_exists('date_popup')) {
+ $formats = date_popup_formats();
+ $default_format = array_shift($formats);
+ }
+ else {
+ // example input formats must show all possible date parts, so add seconds.
+ $formats = str_replace('i', 'i:s', array_keys(date_get_formats('short')));
+ $formats = drupal_map_assoc($formats);
+ $default_format = str_replace('i', 'i:s', variable_get('date_format_short', 'm/d/Y - H:i'));
+ }
+ $now = date_example_date();
+ foreach ($formats as $f) {
+ $options[$f] = date_format_date($now, 'custom', $f);
+ }
+ $form['input']['input_format'] = array(
+ '#type' => 'select', '#title' => t('Input format'),
+ '#default_value' => !empty($widget['input_format']) ? $widget['input_format'] : $default_format,
+ '#options' => $options,
+ '#description' => t('Set the order and format for the date parts in the input form. The format will be adapted to remove values not in the granularity for this field.'),
+ );
+
+ // Only a limited set of formats is available for the Date Popup module
+ if ($widget['type'] != 'date_popup') {
+ $form['input']['format']['input_format_custom'] = array(
+ '#type' => 'textfield', '#title' => t('Custom input format'),
+ '#default_value' => !empty($widget['input_format_custom']) ? $widget['input_format_custom'] : '',
+ '#description' => t("The custom format, if provided, will override the input format selected above. The custom format, if provided, will override the selected display or input options. Define a php date format string like 'm-d-Y H:i' (see http://php.net/date for more details).", array('@link' => 'http://php.net/date')),
+ );
+ }
+ else {
+ $form['input']['format']['input_format_custom'] = array(
+ '#type' => 'hidden',
+ '#value' => '',
+ );
+ }
+ if (in_array($widget['type'], array('date_select', 'date_popup', 'date_select_repeat', 'date_popup_repeat'))) {
+ $form['input']['year_range'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Years back and forward'),
+ '#default_value' => !empty($widget['year_range']) ? $widget['year_range'] : '-3:+3',
+ '#size' => 10,
+ '#maxsize' => 10,
+ '#description' => t('Number of years to go back and forward in the year selection list, default is -3:+3.'),
+ );
+ $form['input']['increment'] = array(
+ '#type' => 'select', '#title' => t('Time increment'),
+ '#default_value' => isset($widget['increment']) ? $widget['increment'] : 1,
+ '#options' => array(1 => 1, 5 => 5, 10 => 10, 15 => 15, 30 => 30),
+ '#description' => t('Increment the minute and second fields by this amount.'),
+ );
+ }
+ else {
+ $form['increment'] = array(
+ '#type' => 'hidden',
+ '#value' => !empty($widget['increment']) ? $widget['increment'] : 1,
+ );
+ $form['year_range'] = array(
+ '#type' => 'hidden',
+ '#value' => isset($widget['year_range']) ? $widget['year_range'] : '-3:+3',
+ );
+ }
+
+ $form['label_position'] = array(
+ '#type' => 'value',
+ '#value' => !empty($widget['label_position']) ? $widget['label_position'] : 'above',
+ );
+ $form['text_parts'] = array(
+ '#type' => 'value',
+ '#value' => isset($widget['text_parts']) ? $widget['text_parts'] : '',
+ );
+ $form['input']['advanced'] = array(
+ '#tree' => TRUE,
+ '#type' => 'fieldset',
+ '#title' => t('Customize Date Parts'),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ );
+ $form['input']['advanced']['label_position'] = array(
+ '#type' => 'radios',
+ '#options' => array('above' => t('Above'), 'within' => t('Within'), 'none' => t('None')),
+ '#default_value' => !empty($widget['label_position']) ? $widget['label_position'] : 'above',
+ '#title' => t('Position of date part labels'),
+ '#description' => t("The location of date part labels, like 'Year', 'Month', or 'Day'. 'Above' will display them as titles above each date part. 'Within' will insert the label as the first option in the select list and in blank textfields. 'None' will not label any of the date parts. The exact text in the label is controlled by themes like 'date_part_label_year' and 'date_part_label_month'."),
+ );
+ $form['input']['advanced']['text_parts'] = array(
+ '#theme' => $widget['type'] == 'date_select' ? 'date_text_parts' : '',
+ );
+ $text_parts = isset($widget['text_parts']) ? (array) $widget['text_parts'] : array();
+ foreach (date_granularity_names() as $key => $value) {
+ if ($widget['type'] == 'date_select') {
+ $form['input']['advanced']['text_parts'][$key] = array(
+ '#type' => 'radios',
+ '#default_value' => in_array($key, $text_parts) ? 1 : 0,
+ '#options' => array(0 => '', 1 => ''),
+ );
+ }
+ else {
+ $form['input']['advanced']['text_parts'][$key] = array(
+ '#type' => 'hidden',
+ '#value' => in_array($key, (array) $widget['text_parts']) ? 1 : 0,
+ );
+ }
+ }
+ return $form;
+}
+
+/**
+ * Display the text/select options for date parts in a table
+ * for easier readability.
+ */
+function theme_date_text_parts($element) {
+ $names = date_granularity_names();
+ $rows = array();
+ foreach ($names as $key => $part) {
+ if ($element[$key]['#type'] == 'hidden') {
+ $rows[] = drupal_render($element[$key]);
+ }
+ else {
+ $rows[] = array($names[$key], drupal_render($element[$key][0]), drupal_render($element[$key][1]));
+ }
+ }
+ if ($element['year']['#type'] == 'hidden') {
+ return implode($rows);
+ }
+ else {
+ $header = array(t('Input Type'), t('Select list'), t('Text field'));
+ return theme('table', $header, $rows);
+ }
+}
+
+/**
+ * Implementation of hook_field_settings().
+ */
+function _date_field_settings($op, $field) {
+ switch ($op) {
+ case 'form':
+ return date_field_settings_form($field);
+
+ case 'validate':
+ if (!in_array('year', $field['granularity'])) {
+ form_set_error('granularity', t('Granularity must include a year.'));
+ }
+ if ($field['tz_handling'] != 'none' && !in_array('hour', array_filter($field['granularity']))) {
+ form_set_error('tz_handling', t('Dates without hours granularity must not use any timezone handling.'));
+ }
+ break;
+
+ case 'save':
+
+ $options = array('granularity', 'timezone_db', 'tz_handling', 'todate', 'repeat', 'repeat_collapsed', 'default_format');
+ return $options;
+
+ case 'database columns':
+ return date_columns($field);
+
+ case 'views data':
+ $data = content_views_field_views_data($field);
+ $db_info = content_database_info($field);
+ $table_alias = content_views_tablename($field);
+
+ // Swap in the date multiple value handler for
+ // CCK's regular multiple value handler.
+ $data[$table_alias][$field['field_name'] .'_value']['field']['handler'] = 'date_handler_field_multiple';
+
+ // Unset the filter and argument handlers, dates can use the generic
+ // date argument and filter handlers created by the Date API.
+ //unset($data[$table_alias][$field['field_name'] .'_value']['argument']);
+ //unset($data[$table_alias][$field['field_name'] .'_value']['filter']);
+ $data[$table_alias][$field['field_name'] .'_value']['argument']['handler'] = 'date_api_argument_handler';
+ $data[$table_alias][$field['field_name'] .'_value']['filter']['handler'] = 'date_api_filter_handler';
+
+ // Add in another set of fields for the To date.
+ if (!empty($field['todate'])) {
+ $data[$table_alias][$field['field_name'] .'_value']['field']['title'] = $data[$table_alias][$field['field_name'] .'_value']['title'];
+ $data[$table_alias][$field['field_name'] .'_value']['field']['title short'] = $data[$table_alias][$field['field_name'] .'_value']['title short'];
+
+ $data[$table_alias][$field['field_name'] .'_value2'] = $data[$table_alias][$field['field_name'] .'_value'];
+
+ $data[$table_alias][$field['field_name'] .'_value']['title'] .= ' - ' . t('From date');
+ $data[$table_alias][$field['field_name'] .'_value']['title short'] .= ' - ' . t('From date');
+ $data[$table_alias][$field['field_name'] .'_value']['field']['title'] .= ' - ' . t('From date');
+ $data[$table_alias][$field['field_name'] .'_value']['field']['title short'] .= ' - ' . t('From date');
+
+ $data[$table_alias][$field['field_name'] .'_value2']['title'] .= ' - ' . t('To date');
+ $data[$table_alias][$field['field_name'] .'_value2']['title short'] .= ' - ' . t('To date');
+ $data[$table_alias][$field['field_name'] .'_value2']['field']['title'] .= ' - ' . t('To date');
+ $data[$table_alias][$field['field_name'] .'_value2']['field']['title short'] .= ' - ' . t('To date');
+
+ $data[$table_alias][$field['field_name'] .'_value2']['field']['field'] .= '2';
+ $data[$table_alias][$field['field_name'] .'_value2']['sort']['field'] .= '2';
+ }
+ return $data;
+ }
+}
+
+/**
+ * Callback for field columns.
+ */
+function date_columns($field) {
+ if ($field['type'] == 'date') {
+ $db_columns['value'] = array('type' => 'varchar', 'length' => 20, 'not null' => FALSE, 'sortable' => TRUE, 'views' => TRUE);
+ }
+ elseif ($field['type'] == 'datestamp') {
+ $db_columns['value'] = array('type' => 'int', 'not null' => FALSE, 'sortable' => TRUE, 'views' => TRUE);
+ }
+ elseif ($field['type'] == 'datetime') {
+ $db_columns['value'] = array('type' => 'datetime', 'not null' => FALSE, 'sortable' => TRUE, 'views' => TRUE);
+ }
+ // If a second date is needed for 'To date', just make a copy of the first one.
+ if (!empty($field['todate'])) {
+ $db_columns['value2'] = $db_columns['value'];
+
+ // We don't want CCK to create additional columns, just the first.
+ // We modify them our own way in views data.
+ $db_columns['value2']['views'] = FALSE;
+ }
+ // timezone and offset columns are used only if date-specific dates are chosen.
+ if (isset($field['tz_handling']) && $field['tz_handling'] == 'date') {
+ $db_columns['timezone'] = array('type' => 'varchar', 'length' => 50, 'not null' => FALSE, 'sortable' => TRUE, 'views' => FALSE);
+ $db_columns['offset'] = array('type' => 'int', 'not null' => FALSE, 'sortable' => TRUE, 'views' => FALSE);
+ if (!empty($field['todate'])) $db_columns['offset2'] = array('type' => 'int', 'not null' => FALSE, 'sortable' => TRUE, 'views' => FALSE);
+ }
+ if (isset($field['repeat']) && $field['repeat'] == 1) {
+ $db_columns['rrule'] = array('type' => 'text', 'not null' => FALSE, 'sortable' => FALSE, 'views' => FALSE);
+ }
+ return $db_columns;
+}
+
+function date_field_settings_form($field) {
+ $form = array(
+ '#element_validate' => array('date_field_settings_validate'),
+ );
+ // Make sure granularity is in the right format and has no empty values.
+ if (!empty($field['granularity']) && is_array($field['granularity'])) {
+ $granularity = array_filter($field['granularity']);
+ }
+ else {
+ $granularity = array('year', 'month', 'day', 'hour', 'minute');
+ }
+ $tz_handling = isset($field['tz_handling']) ? $field['tz_handling'] : (date_has_time($granularity) ? 'site' : 'none');
+
+ // If adding a repeat, override the Content module's handling of the multiple values option.
+ if (module_exists('date_repeat') && date_is_repeat_field($field)) {
+ $form['multiple'] = array('#type' => 'hidden', '#value' => 1);
+ $form['repeat'] = array('#type' => 'hidden', '#value' => 1);
+ }
+ else {
+ $form['repeat'] = array('#type' => 'hidden', '#value' => 0);
+ }
+
+ $description = t("Display a matching second date field as a 'To date'. If marked 'Optional' field will be presented but not required. If marked 'Required' the 'To date' will be required if the 'From date' is required or filled in.");
+ $description .= date_data_loss_warning('To date');
+ $form['input']['todate'] = array(
+ '#type' => 'radios', '#title' => t('To Date'),
+ '#options' => array('' => t('Never'), 'optional' => t('Optional'), 'required' => t('Required')),
+ '#description' => $description,
+ '#default_value' => isset($field['todate']) ? $field['todate'] : '',
+ );
+ $form['input']['granularity'] = array(
+ '#type' => 'select', '#title' => t('Granularity'),
+ '#default_value' => $granularity,
+ '#options' => date_granularity_names(),
+ '#multiple' => TRUE,
+ '#description' => t('Set the date elements to be stored (at least a year is required).'),
+ );
+ $format_types = array();
+ foreach (date_get_format_types('', TRUE) as $name => $info) {
+ $format_types[$name] = $info['title'];
+ }
+ $form['default_format'] = array(
+ '#type' => 'select',
+ '#title' => t('Default Display'),
+ '#default_value' => !empty($field['default_format']) ? $field['default_format'] : 'medium',
+ '#options' => $format_types,
+ '#description' => t('Select a default format type to be used for the date display. Visit the Date and time date format page to add and edit format types.', array('@date-time-page' => url('admin/settings/date-time/formats'))),
+ );
+
+ $description = t('Select the timezone handling method to be used for this date field.');
+ $description .= date_data_loss_warning('Time zone handling');
+ $form['tz_handling'] = array(
+ '#type' => 'select',
+ '#title' => t('Time zone handling'),
+ '#default_value' => $tz_handling,
+ '#options' => date_timezone_handling_options(),
+ '#description' => $description,
+ );
+ // Force this value to hidden because we don't want to allow it to be changed right now,
+ // but allow it to be a variable if needed.
+ $form['timezone_db'] = array(
+ '#type' => 'hidden',
+ '#value' => date_get_timezone_db($tz_handling),
+ );
+
+ if (module_exists('date_repeat') && date_is_repeat_field($field)) {
+ $form['repeat_collapsed'] = array(
+ '#type' => 'radios',
+ '#default_value' => !empty($field['repeat_collapsed']) ? intval($field['repeat_collapsed']) : 0,
+ '#options' => array(0 => t('Expanded'), 1 => t('Collapsed')),
+ '#title' => t('Repeat display'),
+ '#description' => t("Should the repeat options form start out expanded or collapsed? Set to 'Collapsed' to make those options less obtrusive."),
+ );
+ }
+
+ return $form;
+}
+
+/**
+ * Custom field settings manipulation.
+ *
+ * CCK field settings can't use form_set_value(),
+ * so do it in a custom function.
+ */
+function date_field_settings_validate(&$form, &$form_state) {
+ if ($form_state['values']['tz_handling'] == 'none') {
+ form_set_value($form['timezone_db'], '', $form_state);
+ }
+ else {
+ form_set_value($form['timezone_db'], date_get_timezone_db($form_state['values']['tz_handling']), $form_state);
+ }
+}
+
+function date_data_loss_warning($name) {
+ return '
' . t('Changing the %name setting after data has been created could result in the loss of data!', array('%name' => $name)) . '
';
+}
+
+/**
+ * Timezone handling options
+ *
+ * the 'none' option will do no timezone conversions and will store and display dates exactly as entered
+ * useful in locales or situations where timezone conversions are not working reliably,
+ * for dates with no times, for historical dates where timezones are irrelevant,
+ * or anytime conversion is unnecessary or undesirable
+ */
+function date_timezone_handling_options() {
+ return array(
+ 'site' => t("Site's time zone"),
+ 'date' => t("Date's time zone"),
+ 'user' => t("User's time zone"),
+ 'utc' => 'UTC',
+ 'none' => t('No time zone conversion'),
+ );
+}
+
+/**
+ * Get an example date and make sure the difference between
+ * month and day and 12 and 24 hours will be clear.
+ */
+function date_example_date() {
+ $now = date_now();
+ if (date_format($now, 'm') == date_format($now, 'd')) {
+ date_modify($now, '+1 day');
+ }
+ if (date_format($now, 'H') == date_format($now, 'h')) {
+ date_modify($now, '+12 hours');
+ }
+ return $now;
+}
+
+/**
+ * Helper function to create a field array with default values for a date
+ * $field, based on field type, widget type, and timezone handling.
+ *
+ * This function can be used to make it easier to create new date fields
+ * in profiles or custom code.
+ *
+ * @param $field_type
+ * Can be 'date', 'datestamp', or 'datetime'.
+ * @param $widget_type
+ * Can be 'date_text', 'date_text_repeat', 'date_select',
+ * 'date_select_repeat', 'date_popup', 'date_popup_repeat'.
+ * @param $tz_handling
+ * Can be 'site', 'date', 'utc', 'none', or 'user'.
+ * @param $overrides
+ * An optional array of field/widget values that should
+ * override the normal defaults.
+ */
+function date_field_default_values($field_type, $widget_type, $tz_handling, $overrides = array()) {
+ module_load_include('inc', 'content', 'includes/content.crud');
+ $repeat_widgets = array('date_select_repeat', 'date_text_repeat', 'date_popup_repeat');
+
+ $base_field_values = array(
+ 'field_name' => '',
+ 'type_name' => '',
+ 'multiple' => in_array($widget_type, $repeat_widgets) ? 1 : 0,
+ 'module' => 'date',
+ 'granularity' => array(
+ 'year' => 'year',
+ 'month' => 'month',
+ 'day' => 'day',
+ 'hour' => 'hour',
+ 'minute' => 'minute',
+ ),
+ 'timezone_db' => date_get_timezone_db($tz_handling),
+ 'tz_handling' => $tz_handling,
+ 'todate' => 'optional',
+ 'repeat' => in_array($widget_type, $repeat_widgets) ? 1 : 0,
+ 'repeat_collapsed' => 0,
+ 'default_format' => 'medium',
+ );
+ $base_widget_values = array(
+ 'label' => '',
+ 'default_value' => 'now',
+ 'default_value_code' => '',
+ 'default_value2' => 'same',
+ 'default_value_code2' => '',
+ 'input_format' => date_default_format($widget_type),
+ 'input_format_custom' => '',
+ 'increment' => 1,
+ 'text_parts' => array(),
+ 'year_range' => '-3:+3',
+ 'label_position' => 'above',
+ 'weight' => 0,
+ 'description' => '',
+ 'module' => 'date',
+ );
+ $field_values['date'] = $base_field_values;
+ $field_values['date']['type'] = 'date';
+
+ $field_values['datestamp'] = $base_field_values;
+ $field_values['datestamp']['type'] = 'datestamp';
+
+ $field_values['datetime'] = $base_field_values;
+ $field_values['datetime']['type'] = 'datetime';
+
+ $widget_values['date_select'] = $base_widget_values;
+ $widget_values['date_select']['type'] = 'date_select';
+
+ $widget_values['date_text'] = $base_widget_values;
+ $widget_values['date_text']['type'] = 'date_text';
+
+ $widget_values['date_popup'] = $base_widget_values;
+ $widget_values['date_popup']['type'] = 'date_popup';
+ $widget_values['date_popup']['module'] = 'date_popup';
+
+ $widget_values['date_select_repeat'] = $base_widget_values;
+ $widget_values['date_select_repeat']['type'] = 'date_select_repeat';
+
+ $widget_values['date_text_repeat'] = $base_widget_values;
+ $widget_values['date_text_repeat']['type'] = 'date_text_repeat';
+
+ $widget_values['date_popup_repeat'] = $base_widget_values;
+ $widget_values['date_popup_repeat']['type'] = 'date_popup_repeat';
+
+ // Get the basic field array with content module default values.
+ $field = content_field_default_values($field_type);
+
+ // Update it with default values for this date field and widget type.
+ foreach ($field_values[$field_type] as $key => $value) {
+ $field[$key] = $value;
+ }
+ foreach ($widget_values[$widget_type] as $key => $value) {
+ $field['widget'][$key] = $value;
+ }
+
+ // Allow overrides of specific default values.
+ foreach ($overrides as $key => $value) {
+ if ($key != 'widget') {
+ $field[$key] = $value;
+ }
+ else {
+ foreach ($value as $widget_key => $widget_value) {
+ $field['widget'][$widget_key] = $widget_value;
+ }
+ }
+ }
+ // Make sure multiple gets set correctly for repeating dates.
+ if ($field['repeat']) $field['multiple'] = 1;
+
+ // Reset columns and db_storage, which may need to be
+ // adjusted to the new values.
+ $field['columns'] = date_columns($field);
+ $field['db_storage'] = content_storage_type($field);
+
+ return $field;
+}
+
+/**
+ * Formatter settings.
+ *
+ * Form element used both in the date_handler_field_multiple Views handler
+ * and on the CCK Display fields page.
+ */
+function _date_formatter_settings($form_state = NULL, $field, $options = array(), $views_form = FALSE) {
+ $field_name = $field['field_name'];
+ $field = content_fields($field_name);
+ $type_name = isset($options['type_name']) ? $options['type_name'] : $field['type_name'];
+ $context = isset($options['context']) ? $options['context'] : 'full';
+ if (empty($options['fromto'])) {
+ $options = date_formatter_get_settings($field_name, $type_name, $context);
+ }
+
+ $form = array();
+ $form['fromto'] = array(
+ '#access' => $field['todate'],
+ '#weight' => 5,
+ );
+ if (isset($options['fromto']) && isset($options['fromto']['fromto'])) {
+ $default = $options['fromto']['fromto'];
+ }
+ else {
+ $default = 'both';
+ }
+ $form['fromto']['fromto'] = array(
+ '#type' => 'select',
+ '#options' => array(
+ 'both' => t('Display From and To dates'),
+ 'value' => t('Display From date only'),
+ 'value2' => t('Display To date only'),
+ ),
+ '#default_value' => $default,
+ '#weight' => 1,
+ );
+
+ $form['multiple'] = array(
+ '#access' => $field['multiple'],
+ '#weight' => 6,
+ );
+
+ // Make the string translatable by keeping it as a whole rather than
+ // translating prefix and suffix separately.
+ if (isset($options['multiple']) && isset($options['multiple']['multiple_number'])) {
+ $default = $options['multiple']['multiple_number'];
+ }
+ else {
+ $default = '';
+ }
+ list($prefix, $suffix) = explode('@count', t('Show @count value(s)'));
+ $form['multiple']['multiple_number'] = array(
+ '#type' => 'textfield',
+ '#size' => 5,
+ '#field_prefix' => theme('advanced_help_topic', 'date_api', 'date-display') . $prefix,
+ '#field_suffix' => $suffix,
+ '#default_value' => $default,
+ '#weight' => 1,
+ );
+ if ($views_form) {
+ $form['multiple']['multiple_number'] += array(
+ '#process' => array('views_process_dependency'),
+ '#dependency' => array('edit-options-multiple-group' => array(TRUE)),
+ );
+ }
+
+ if (isset($options['multiple']) && isset($options['multiple']['multiple_from'])) {
+ $default = $options['multiple']['multiple_from'];
+ }
+ else {
+ $default = '';
+ }
+ list($prefix, $suffix) = explode('@count', t('starting from @count'));
+ $form['multiple']['multiple_from'] = array(
+ '#type' => 'textfield',
+ '#size' => 15,
+ '#field_prefix' => $prefix,
+ '#field_suffix' => $suffix,
+ '#default_value' => $default,
+ '#weight' => 2,
+ );
+ if ($views_form) {
+ $form['multiple']['multiple_from'] += array(
+ '#process' => array('views_process_dependency'),
+ '#dependency' => array('edit-options-multiple-group' => array(TRUE)),
+ );
+ }
+
+ if (isset($options['multiple']) && isset($options['multiple']['multiple_to'])) {
+ $default = $options['multiple']['multiple_to'];
+ }
+ else {
+ $default = '';
+ }
+ list($prefix, $suffix) = explode('@count', t('ending on @count'));
+ $form['multiple']['multiple_to'] = array(
+ '#type' => 'textfield',
+ '#size' => 15,
+ '#field_prefix' => $prefix,
+ '#field_suffix' => $suffix,
+ '#default_value' => $default,
+ '#weight' => 3,
+ );
+ if ($views_form) {
+ $form['multiple']['multiple_to'] += array(
+ '#process' => array('views_process_dependency'),
+ '#dependency' => array('edit-options-multiple-group' => array(TRUE)),
+ );
+ }
+
+ $form['repeat'] = array(
+ '#access' => $field['repeat'],
+ '#weight' => 7,
+ );
+ if (isset($options['repeat']) && isset($options['repeat']['show_repeat_rule'])) {
+ $default = $options['repeat']['show_repeat_rule'];
+ }
+ else {
+ $default = 'show';
+ }
+ $form['repeat']['show_repeat_rule'] = array(
+ '#type' => 'select',
+ '#options' => array(
+ 'show' => t('Display repeat rule'),
+ 'hide' => t('Hide repeat rule')),
+ '#default_value' => $default,
+ );
+
+ if (!$views_form) {
+ $form['field'] = array(
+ '#type' => 'value',
+ '#value' => $field,
+ );
+ $form['type_name'] = array(
+ '#type' => 'value',
+ '#value' => $type_name,
+ );
+ $form['context'] = array(
+ '#type' => 'value',
+ '#value' => $context,
+ );
+ }
+ return $form;
+}
\ No newline at end of file
diff --git a/sites/all/modules/date/date/date_content_generate.inc b/sites/all/modules/date/date/date_content_generate.inc
new file mode 100644
index 0000000..4e1c6ac
--- /dev/null
+++ b/sites/all/modules/date/date/date_content_generate.inc
@@ -0,0 +1,185 @@
+ $until, 'tz' => 'UTC');
+ $form_values['COUNT'] = $max_items;
+
+ $rrule = date_api_ical_build_rrule($form_values);
+ $values = date_repeat_build_dates($rrule, $form_values, $field, $node_field);
+
+ $start = $node_field;
+ $node_field = array(0 => $start);
+ $node_field[0]['rrule'] = $rrule;
+ $node_field += $values;
+ }
+ return $node_field;
+}
+
+function date_content_generate_key($array) {
+ $keys = array_keys($array);
+ $min = array_shift($keys);
+ $max = array_pop($keys);
+ return mt_rand($min, $max);
+}
+
+/**
+ * Helper function for BYDAY options.
+ *
+ * Creates options like -1SU and 2TU
+ * Omit options that won't find many matches, like 5th Sunday.
+ */
+function date_content_repeat_dow_options() {
+ $options = array();
+ foreach (date_repeat_dow_count_options() as $count_key => $count_value) {
+ foreach (date_repeat_dow_day_options() as $dow_key => $dow_value) {
+ if ($count_key != 5 && $count_key != -5) {
+ $options[$count_key . $dow_key] = $count_value .' '. $dow_value;
+ }
+ }
+ }
+ return $options;
+}
\ No newline at end of file
diff --git a/sites/all/modules/date/date/date_elements.inc b/sites/all/modules/date/date/date_elements.inc
new file mode 100644
index 0000000..273d8e2
--- /dev/null
+++ b/sites/all/modules/date/date/date_elements.inc
@@ -0,0 +1,586 @@
+ $item) {
+ $process = date_process_values($field);
+ foreach ($process as $processed) {
+ $error_field = $field['field_name'] .']['. $delta .']['. $processed;
+ $error_field .= $field['widget']['type'] == 'date_select' ? '][year' : '';
+ if ($processed == 'value' && $field['todate']
+ && !date_is_valid($item['value'], $field['type'], $field['granularity'])
+ && (date_is_valid($item['value2'], $field['type'], $field['granularity']))) {
+ form_set_error($error_field, t("A 'From date' date is required for field %field %delta.", array('%delta' => $field['multiple'] ? intval($delta + 1) : '', '%field' => t($field['widget']['label']))));
+ }
+ if ($processed == 'value2'
+ && $field['todate'] == 'required' && ($field['required']
+ && date_is_valid($item['value'], $field['type'], $field['granularity'])
+ && !date_is_valid($item['value2'], $field['type'], $field['granularity']))) {
+ form_set_error($error_field, t("A 'To date' is required for field %field %delta.", array('%delta' => $field['multiple'] ? intval($delta + 1) : '', '%field' => t($field['widget']['label']))));
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Private implementation of hook_field update and insert operations.
+ */
+function _date_field_update($op, &$node, $field, &$items, $teaser, $page) {
+ $field_name = $field['field_name'];
+ if (empty($items)) {
+ //$node->$field_name = array(); // Not sure about this, CCK should handle it.
+ return;
+ }
+
+ $values = $items;
+ foreach ($values as $delta => $item) {
+
+ // Special case for ISO dates which may have been given artificial values for
+ // some date parts to make them into valid dates.
+ if (!empty($item['value']) && $field['type'] == DATE_ISO) {
+ $items[$delta]['value'] = date_limit_value($items[$delta]['value'], date_granularity($field), $field['type']);
+ if ($field['todate']) {
+ $items[$delta]['value2'] = date_limit_value($items[$delta]['value2'], date_granularity($field), $field['type']);
+ }
+ }
+ }
+ $node->$field['field_name'] = $items;
+}
+
+/**
+ * Private implementation of hook_widget().
+ *
+ * The widget builds out a complex date element in the following way:
+ *
+ * - A field is pulled out of the database which is comprised of one or
+ * more collections of from/to dates.
+ *
+ * - The dates in this field are all converted from the UTC values stored
+ * in the database back to the local time before passing their values
+ * to FAPI.
+ *
+ * - If values are empty, the field settings rules are used to determine
+ * if the default_values should be empty, now, the same, or use strtotime.
+ *
+ * - Each from/to combination is created using the date_combo element type
+ * defined by the date module. If the timezone is date-specific, a
+ * timezone selector is added to the first combo element.
+ *
+ * - If repeating dates are defined, a form to create a repeat rule is
+ * added to the field element.
+ *
+ * - The date combo element creates two individual date elements, one each
+ * for the from and to field, using the appropriate individual Date API
+ * date elements, like selects, textfields, or popups.
+ *
+ * - In the individual element validation, the data supplied by the user is
+ * used to update the individual date values.
+ *
+ * - In the combo date validation, the timezone is updated, if necessary,
+ * then the user input date values are used with that timezone to create
+ * date objects, which are used update combo date timezone and offset values.
+ *
+ * - In the field's submission processing, the new date values, which are in
+ * the local timezone, are converted back to their UTC values and stored.
+ *
+ */
+function _date_widget(&$form, &$form_state, &$field, $items, $delta = 0) {
+
+ // Be sure users that haven't run the update yet don't get
+ // a badly broken value.
+ if (!empty($field['repeat']) && !strstr($field['widget']['type'], '_repeat')) {
+ $field['multiple'] = 0;
+ return;
+ }
+
+ require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_elements.inc');
+ $timezone = date_get_timezone($field['tz_handling'], isset($items[0]['timezone']) ? $items[0]['timezone'] : date_default_timezone_name());
+ // TODO see if there's a way to keep the timezone element from ever being
+ // nested as array('timezone' => 'timezone' => value)). After struggling
+ // with this a while, I can find no way to get it displayed in the form
+ // correctly and get it to use the timezone element without ending up
+ // with nesting.
+ if (is_array($timezone)) {
+ $timezone = $timezone['timezone'];
+ }
+
+ // Convert UTC dates to their local values in DATETIME format,
+ // and adjust the default values as specified in the field settings.
+
+ // It would seem to make sense to do this conversion when the data
+ // is loaded instead of when the form is created, but the loaded
+ // field data is cached and we can't cache dates that have been converted
+ // to the timezone of an individual user, so we cache the UTC values
+ // instead and do our conversion to local dates in the form and
+ // in the formatters.
+ $process = date_process_values($field);
+ foreach ($process as $processed) {
+ if (!isset($items[$delta][$processed])) {
+ $items[$delta][$processed] = '';
+ }
+ $date = date_local_date($form, $form_state, $delta, $items[$delta], $timezone, $field, $processed);
+ $items[$delta][$processed] = is_object($date) ? date_format($date, DATE_FORMAT_DATETIME) : '';
+ }
+
+ $element = array(
+ '#type' => 'date_combo',
+ '#weight' => $delta,
+ '#default_value' => isset($items[$delta]) ? $items[$delta] : '',
+ '#date_timezone' => $timezone,
+ '#element_validate' => array('date_combo_validate', 'date_widget_validate'),
+ );
+
+ if ($field['tz_handling'] == 'date') {
+ $element['timezone'] = array(
+ '#type' => 'date_timezone',
+ '#delta' => $delta,
+ '#default_value' => $timezone,
+ '#weight' => $field['widget']['weight'] + .2,
+ );
+ }
+
+ // Add a date repeat form element, if needed.
+ if (module_exists('date_repeat') && $field['repeat'] == 1) {
+ require_once('./'. drupal_get_path('module', 'date') .'/date_repeat.inc');
+ _date_repeat_widget($element, $field, $items, $delta);
+ $element['rrule']['#weight'] = $field['widget']['weight'] + .4;
+ }
+ return $element;
+}
+
+/**
+ * Create local date object.
+ *
+ * Create a date object set to local time from the field and
+ * widget settings and item values, using field settings to
+ * determine what to do with empty values.
+ */
+function date_local_date($form, $form_state, $delta, $item, $timezone, $field, $part = 'value') {
+ if (!empty($form['nid']['#value'])) {
+ $default_value = '';
+ $default_value_code = '';
+ }
+ elseif ($part == 'value') {
+ $default_value = $field['widget']['default_value'];
+ $default_value_code = $field['widget']['default_value_code'];
+ }
+ else {
+ $default_value = $field['widget']['default_value2'];
+ $default_value_code = $field['widget']['default_value_code2'];
+ }
+ if (empty($item) || empty($item[$part])) {
+ if (empty($default_value) || $default_value == 'blank' || $delta > 0) {
+ return NULL;
+ }
+ elseif ($part == 'value2' && $default_value == 'same') {
+ if ($field['widget']['default_value'] == 'blank' || empty($item['value'])) {
+ return NULL;
+ }
+ else {
+ $date = date_make_date($item['value'], $timezone, DATE_DATETIME, $field['granularity']);
+ }
+ }
+ // Special case for 'now' when using dates with no timezone,
+ // make sure 'now' isn't adjusted to UTC value of 'now'.
+ elseif ($field['tz_handling'] == 'none') {
+ $date = date_now();
+ }
+ else {
+ $date = date_now($timezone);
+ }
+ }
+ else {
+ $value = $item[$part];
+
+ // Special case for ISO dates to create a valid date object for formatting.
+ if ($field['type'] == DATE_ISO) {
+ $value = date_fuzzy_datetime($value);
+ }
+ else {
+ $db_timezone = date_get_timezone_db($field['tz_handling']);
+ $value = date_convert($value, $field['type'], DATE_DATETIME, $db_timezone);
+ }
+ $date = date_make_date($value, date_get_timezone_db($field['tz_handling']), DATE_DATETIME, $field['granularity']);
+ if (empty($date)) {
+ return NULL;
+ }
+ date_timezone_set($date, timezone_open($timezone));
+ }
+ if (is_object($date) && empty($item[$part]) && $default_value == 'strtotime' && !empty($default_value_code)) {
+ date_modify($date, $default_value_code);
+ }
+ return $date;
+}
+
+/**
+ * Implementation of hook_elements().
+ *
+ * date_combo will create a 'from' and optional 'to' date, along with
+ * an optional 'timezone' column for date-specific timezones. Each
+ * 'from' and 'to' date will be constructed from date_select or date_text.
+ */
+function _date_elements() {
+ $type = array();
+ $type['date_combo'] = array(
+ '#input' => TRUE,
+ '#delta' => 0,
+ '#columns' => array('value', 'value2', 'timezone', 'offset', 'offset2'),
+ '#process' => array('date_combo_process'),
+ '#element_validate' => array('date_combo_validate'),
+ );
+ return $type;
+}
+
+/**
+ * Process an individual date element.
+ */
+function date_combo_process($element, $edit, &$form_state, $form) {
+ if (isset($element['#access']) && empty($element['#access'])) {
+ return $element;
+ }
+
+ $field_name = $element['#field_name'];
+ $field = $form['#field_info'][$field_name];
+ $delta = $element['#delta'];
+
+ $columns = $element['#columns'];
+ if (isset($columns['rrule'])) {
+ unset($columns['rrule']);
+ }
+ $from_field = 'value';
+ $to_field = 'value2';
+ $tz_field = 'timezone';
+ $offset_field = 'offset';
+ $offset_field2 = 'offset2';
+
+ if ($field['todate'] != 'required' && !empty($element['#default_value'][$to_field]) && $element['#default_value'][$to_field] == $element['#default_value'][$from_field]) {
+ unset($element['#default_value'][$to_field]);
+ }
+
+ $element[$from_field] = array(
+ '#field' => $field,
+ '#title' => (!$field['multiple'] || $field['repeat']) ? t($field['widget']['label']) : '',
+ '#weight' => $field['widget']['weight'],
+ '#required' => ($field['required'] && $delta == 0) ? 1 : 0,
+ '#default_value' => isset($element['#value'][$from_field]) ? $element['#value'][$from_field] : '',
+ '#delta' => $delta,
+ '#date_timezone' => $element['#date_timezone'],
+ '#date_format' => date_limit_format(date_input_format($element, $field), $field['granularity']),
+ '#date_text_parts' => (array) $field['widget']['text_parts'],
+ '#date_increment' => $field['widget']['increment'],
+ '#date_year_range' => $field['widget']['year_range'],
+ '#date_label_position' => $field['widget']['label_position'],
+ );
+
+ $description = !empty($field['widget']['description']) ? t($field['widget']['description']) : '';
+
+ // Give this element the right type, using a Date API
+ // or a Date Popup element type.
+
+ switch ($field['widget']['type']) {
+ case 'date_select':
+ case 'date_select_repeat':
+ // From/to selectors with lots of parts will look better if displayed
+ // on two rows instead of in a single row.
+ if (!empty($field['todate']) && count($field['granularity']) > 3) {
+ $element[$from_field]['#attributes'] = array('class' => 'date-clear');
+ }
+ $element[$from_field]['#type'] = 'date_select';
+ break;
+ case 'date_popup':
+ case 'date_popup_repeat':
+ $element[$from_field]['#type'] = 'date_popup';
+ break;
+ default:
+ $element[$from_field]['#type'] = 'date_text';
+ break;
+ }
+
+ // If this field uses the 'To', add matching element
+ // for the 'To' date, and adapt titles to make it clear which
+ // is the 'From' and which is the 'To'.
+
+ if (!empty($field['todate'])) {
+ $element['#date_float'] = TRUE;
+ $element[$from_field]['#title'] = t('From date');
+ $element[$to_field] = $element[$from_field];
+ $element[$to_field]['#title'] = t('To date');
+ $element[$to_field]['#default_value'] = isset($element['#value'][$to_field]) ? $element['#value'][$to_field] : '';
+ $element[$to_field]['#required'] = FALSE;
+ $element[$to_field]['#weight'] += .1;
+ if (($field['widget']['type'] == 'date_select') && empty($description)) {
+ $description = t("Empty 'To date' values will use the 'From date' values.");
+ }
+ else {
+ if (trim($description) == "") {
+ $description = NULL;
+ }
+ }
+ $element['#fieldset_description'] = $description;
+ }
+ else {
+ $element[$from_field]['#description'] = $description;
+ }
+
+ // Create label for error messages that make sense in multiple values
+ // and when the title field is left blank.
+ if (!empty($field['multiple']) && empty($field['repeat'])) {
+ $element[$from_field]['#date_title'] = t('@field_name From date value #@delta', array('@field_name' => $field['widget']['label'], '@delta' => $delta + 1));
+ if (!empty($field['todate'])) {
+ $element[$to_field]['#date_title'] = t('@field_name To date value #@delta', array('@field_name' => $field['widget']['label'], '@delta' => $delta + 1));
+ }
+ }
+ elseif (!empty($field['todate'])) {
+ $element[$from_field]['#date_title'] = t('@field_name From date', array('@field_name' => $field['widget']['label']));
+ $element[$to_field]['#date_title'] = t('@field_name To date', array('@field_name' => $field['widget']['label']));
+ }
+ else {
+ $element[$from_field]['#date_title'] = $field['widget']['label'];
+ }
+
+ // Make sure field info will be available to the validator which
+ // does not get the values in $form.
+ $form_state['#field_info'][$field['field_name']] = $field;
+ return $element;
+}
+
+function date_element_empty($element, &$form_state) {
+ $item = array();
+ $item['value'] = NULL;
+ $item['value2'] = NULL;
+ $item['timezone'] = NULL;
+ $item['offset'] = NULL;
+ $item['offset2'] = NULL;
+ $item['rrule'] = NULL;
+ form_set_value($element, $item, $form_state);
+ return $item;
+}
+
+/**
+ * Validate and update a combo element.
+ * Don't try this if there were errors before reaching this point.
+ */
+function date_combo_validate($element, &$form_state) {
+ $form_values = $form_state['values'];
+ $field_name = $element['#field_name'];
+ $delta = $element['#delta'];
+
+ // If the whole field is empty and that's OK, stop now.
+ if (empty($element['#post'][$field_name]) && !$element['#required']) {
+ return;
+ }
+
+ // Repeating dates have a different form structure, so get the
+ // right item values.
+ $item = isset($form_values[$field_name]['rrule']) ? $form_values[$field_name] : $form_values[$field_name][$delta];
+ $posted = isset($form_values[$field_name]['rrule']) ? $element['#post'][$field_name] : $element['#post'][$field_name][$delta];
+
+ $field = $form_state['#field_info'][$element['#field_name']];
+ $from_field = 'value';
+ $to_field = 'value2';
+ $tz_field = 'timezone';
+ $offset_field = 'offset';
+ $offset_field2 = 'offset2';
+
+ // Unfortunately, due to the fact that much of the processing is already
+ // done by the time we get here, it is not possible highlight the field
+ // with an error, we just try to explain which element is creating the
+ // problem in the error message.
+ $parent = $element['#parents'];
+ $error_field = array_pop($parent);
+ $errors = array();
+
+ // Check for empty 'From date', which could either be an empty
+ // value or an array of empty values, depending on the widget.
+ $empty = TRUE;
+ if (!empty($item[$from_field])) {
+ if (!is_array($item[$from_field])) {
+ $empty = FALSE;
+ }
+ else {
+ foreach ($item[$from_field] as $key => $value) {
+ if (!empty($value)) {
+ $empty = FALSE;
+ break;
+ }
+ }
+ }
+ }
+ if ($empty) {
+ $item = date_element_empty($element, $form_state);
+ if (!$element['#required']) {
+ return;
+ }
+ }
+ // Don't look for further errors if errors are already flagged
+ // because otherwise we'll show errors on the nested elements
+ // more than once.
+ elseif (!form_get_errors()) {
+
+ // Check todate input for blank values and substitute in fromdate
+ // values where needed, then re-compute the todate with those values.
+ if ($field['todate']) {
+ $merged_date = array();
+ $to_date_empty = TRUE;
+ foreach ($posted[$to_field] as $part => $value) {
+ $to_date_empty = $to_date_empty && empty($value) && !is_numeric($value);
+ $merged_date[$part] = empty($value) && !is_numeric($value) ? $posted[$from_field][$part] : $value;
+ if ($part == 'ampm' && $merged_date['ampm'] == 'pm' && $merged_date['hour'] < 12) {
+ $merged_date['hour'] += 12;
+ }
+ elseif ($part == 'ampm' && $merged_date['ampm'] == 'am' && $merged_date['hour'] == 12) {
+ $merged_date['hour'] -= 12;
+ }
+ }
+
+ // If all date values were empty and a date is required, throw
+ // an error on the first element. We don't want to create
+ // duplicate messages on every date part, so the error will
+ // only go on the first.
+ if ($to_date_empty && $field['todate'] == 'required') {
+ $errors[] = t('Some value must be entered in the To date.');
+ }
+
+ $element[$to_field]['#value'] = $merged_date;
+
+ // Call the right function to turn this altered user input into
+ // a new value for the todate.
+ $item[$to_field] = $merged_date;
+ }
+ else {
+ $item[$to_field] = $item[$from_field];
+ }
+
+ $from_date = date_input_value($field, $element[$from_field]);
+ if (!empty($field['todate'])) {
+ $to_date = date_input_value($field, $element[$to_field]);
+ }
+ else {
+ $to_date = $from_date;
+ }
+
+ // Neither the from date nor the to date should be empty at this point
+ // unless they held values that couldn't be evaluated.
+ if (!$field['required'] && (empty($from_date) || empty($to_date))) {
+ $item = date_element_empty($element, $form_state);
+ $errors[] = t('The dates are invalid.');
+ }
+ elseif (!empty($field['todate']) && $from_date > $to_date) {
+ form_set_value($element[$to_field], $to_date, $form_state);
+ $errors[] = t('The To date must be greater than the From date.');
+ }
+ else {
+ // Convert input dates back to their UTC values and re-format to ISO
+ // or UNIX instead of the DATETIME format used in element processing.
+ $timezone = !empty($item[$tz_field]) ? $item[$tz_field] : $element['#date_timezone'];
+ $timezone_db = date_get_timezone_db($field['tz_handling']);
+
+ $item[$tz_field] = $timezone;
+
+ $from_date = date_make_date($from_date, $timezone);
+ $item[$offset_field] = date_offset_get($from_date);
+
+ $to_date = date_make_date($to_date, $timezone);
+ $test_from = date_format($from_date, 'r');
+ $test_to = date_format($to_date, 'r');
+ $item[$offset_field2] = date_offset_get($to_date);
+ date_timezone_set($from_date, timezone_open($timezone_db));
+ date_timezone_set($to_date, timezone_open($timezone_db));
+ $item[$from_field] = date_format($from_date, date_type_format($field['type']));
+ $item[$to_field] = date_format($to_date, date_type_format($field['type']));
+ if (isset($form_values[$field_name]['rrule'])) {
+ $item['rrule'] = $form_values[$field['field_name']]['rrule'];
+ }
+
+ // If the db timezone is not the same as the display timezone
+ // and we are using a date with time granularity,
+ // test a roundtrip back to the original timezone to catch
+ // invalid dates, like 2AM on the day that spring daylight savings
+ // time begins in the US.
+ $granularity = date_format_order($element[$from_field]['#date_format']);
+ if ($timezone != $timezone_db && date_has_time($granularity)) {
+ date_timezone_set($from_date, timezone_open($timezone));
+ date_timezone_set($to_date, timezone_open($timezone));
+
+ if ($test_from != date_format($from_date, 'r')) {
+ $errors[] = t('The From date is invalid.');
+ }
+ if ($test_to != date_format($to_date, 'r')) {
+ $errors[] = t('The To date is invalid.');
+ }
+ }
+
+ if (empty($errors)) {
+ form_set_value($element, $item, $form_state);
+ }
+ }
+ }
+ if (!empty($errors)) {
+ if ($field['multiple']) {
+ form_set_error($error_field, t('There are errors in @field_name value #@delta:', array('@field_name' => $field['widget']['label'], '@delta' => $delta + 1)) . theme('item_list', $errors));
+ }
+ else {
+ form_set_error($error_field, t('There are errors in @field_name:', array('@field_name' => $field['widget']['label'])) . theme('item_list', $errors));
+ }
+ }
+}
+
+/**
+ * Handle widget processing.
+ */
+function date_widget_validate($element, &$form_state) {
+ $field = $form_state['#field_info'][$element['#field_name']];
+ if (module_exists('date_repeat') && $field['repeat'] == 1) {
+ module_load_include('inc', 'date', 'date_repeat');
+ return _date_repeat_widget_validate($element, $form_state);
+ }
+}
+
+/**
+ * Determine the input format for this element.
+ */
+function date_input_format($element, $field) {
+ if (!empty($field['widget']['input_format_custom'])) {
+ return $field['widget']['input_format_custom'];
+ }
+ elseif (!empty($field['widget']['input_format']) && $field['widget']['input_format'] != 'site-wide') {
+ return $field['widget']['input_format'];
+ }
+ return variable_get('date_format_short', 'm/d/Y - H:i');
+}
+
+/**
+ * Theme from/to date combination on form.
+ */
+function theme_date_combo($element) {
+ $field = content_fields($element['#field_name'], $element['#type_name']);
+ if (!$field['todate']) {
+ return $element['#children'];
+ }
+
+ // Group from/to items together in fieldset.
+ $fieldset = array(
+ '#title' => check_plain($field['widget']['label']) .' '. ($element['#delta'] > 0 ? intval($element['#delta'] + 1) : ''),
+ '#value' => $element['#children'],
+ '#collapsible' => FALSE,
+ '#collapsed' => FALSE,
+ '#description' => $element['#fieldset_description'],
+ '#attributes' => array(),
+ );
+ return theme('fieldset', $fieldset);
+}
diff --git a/sites/all/modules/date/date/date_handler_field_multiple.inc b/sites/all/modules/date/date/date_handler_field_multiple.inc
new file mode 100644
index 0000000..7cec65b
--- /dev/null
+++ b/sites/all/modules/date/date/date_handler_field_multiple.inc
@@ -0,0 +1,186 @@
+ array(
+ 'show_repeat_rule' => array('default' => ''),
+ )
+ );
+ $options['multiple'] = array(
+ 'contains' => array(
+ 'group' => array('default' => TRUE),
+ 'multiple_number' => array('default' => ''),
+ 'multiple_from' => array('default' => ''),
+ 'multiple_to' => array('default' => ''),
+ )
+ );
+ $options['fromto'] = array(
+ 'contains' => array(
+ 'fromto' => array('default' => 'both'),
+ )
+ );
+
+ return $options;
+ }
+
+ /**
+ * Provide 'group multiple values' option,
+ * adapted to the needs of the Date module.
+ */
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+ unset($form['multiple']);
+
+ $field = $this->content_field;
+ $options = $this->options;
+
+ $form += date_formatter_settings($form_state, $field, $options, TRUE);
+ $form['multiple']['#weight'] = 1;
+ $form['multiple']['group'] = array(
+ '#title' => t('Group multiple values'),
+ '#type' => 'checkbox',
+ '#default_value' => $options['multiple']['group'],
+ '#description' => t('If unchecked, each item in the field will create a new row, which may appear to cause duplicates. This setting is not compatible with click-sorting in table displays.'),
+ );
+ }
+
+ function pre_render(&$values) {
+
+ // If there are no values to render (displaying a summary, or query returned no results),
+ // or if this is not a grouped field, do nothing specific.
+ if (isset($this->view->build_info['summary']) || empty($values) || !$this->defer_query) {
+ return parent::pre_render($values);
+ }
+ $field = $this->content_field;
+ $db_info = content_database_info($field);
+ $options = $this->options;
+ $this->view->date_info->date_handler_fields = date_handler_fields($this->view);
+
+ // Build the list of vids to retrieve.
+ // TODO: try fetching from cache_content first ??
+ $vids = array();
+ $this->field_values = array();
+ foreach ($values as $result) {
+ if (isset($result->{$this->field_alias})) {
+ $vids[] = $result->{$this->field_alias};
+ }
+ }
+
+ // List columns to retrieve.
+ $alias = content_views_tablename($field);
+ // Prefix aliases with '_' to avoid clashing with field columns names.
+ $query_columns = array(
+ 'node.vid AS _vid',
+ "$alias.delta as _delta",
+ // nid is needed to generate the links for 'link to node' option.
+ 'node.nid AS _nid',
+ );
+ // The actual field columns.
+ foreach ($db_info['columns'] as $column => $attributes) {
+ $query_columns[] = "$alias.$attributes[column] AS $column";
+ $query_fields[] = "$alias.$attributes[column]";
+ }
+ // Retrieve all values, we limit them in date_prepare_node(),
+ // a function that is used both by the handler and by the
+ // node theme to take advantage of formatter settings.
+ $where = array('1');
+ $query = 'SELECT '. implode(', ', $query_columns) .
+ ' FROM {'. $db_info['table'] ."} $alias".
+ " LEFT JOIN {node} node ON node.vid = $alias.vid".
+ " WHERE node.vid IN (". implode(',', $vids) .') AND '. implode(' OR ', $where) .
+ " ORDER BY node.nid ASC, $alias.delta ASC";
+ $result = db_query($query);
+
+ while ($item = db_fetch_array($result)) {
+ // Clean up the $item from vid and delta. We keep nid for now.
+ $vid = $item['_vid'];
+ unset($item['_vid']);
+ $delta = !empty($item['_delta']) ? $item['_delta'] : 0;
+ $item['#delta'] = $item['_delta'];
+ unset($item['_delta']);
+ $this->field_values[$vid][$delta] = $item;
+ }
+ }
+
+ function render($values) {
+
+ // By this time $values is a pseudo node that will be passed
+ // to the theme. Add view information to it.
+ $values->date_info = !empty($this->view->date_info) ? $this->view->date_info : new stdClass();
+ $values->date_info->date_handler_fields = date_handler_fields($this->view);
+
+ // Add the formatter settings to the pseudo node.
+ $values->date_info->formatter_settings = $this->options;
+ $values->date_info->aliases = $this->aliases;
+
+ // If this is not a grouped field, use content_handler_field::render().
+ if (!$this->defer_query) {
+ return parent::render($values);
+ }
+
+ $field = $this->content_field;
+ $field_name = $field['field_name'];
+ $options = $this->options;
+
+ $vid = $values->{$this->field_alias};
+ if (isset($this->field_values[$vid])) {
+ // Build a pseudo-node from the retrieved values.
+ $node = drupal_clone($values);
+ // content_format and formatters will need a 'type'.
+ $node->type = $values->{$this->aliases['type']};
+ $node->nid = $values->{$this->aliases['nid']};
+ $node->vid = $values->{$this->aliases['vid']};
+ $items = $this->field_values[$vid];
+ $node->$field_name = $items;
+
+ // Some formatters need to behave differently depending on the build_mode
+ // (for instance: preview), so we provide one.
+ $node->build_mode = NODE_BUILD_NORMAL;
+
+ // Render items.
+ $formatter_name = $options['format'];
+ if ($items && ($formatter = _content_get_formatter($formatter_name, $field['type']))) {
+ $rendered = array();
+ if (content_handle('formatter', 'multiple values', $formatter) == CONTENT_HANDLE_CORE) {
+ // Single-value formatter.
+ foreach ($items as $item) {
+ $output = content_format($field, $item, $formatter_name, $node);
+ if (!empty($output)) {
+ $rendered[] = $this->render_link($output, (object) array('nid' => $this->aliases['nid']));
+ }
+ }
+ }
+ else {
+ // Multiple values formatter.
+ $output = content_format($field, $items, $formatter_name, $values);
+ if (!empty($output)) {
+ $rendered[] = $this->render_link($output, (object) array('nid' => $this->aliases['nid']));
+ }
+ }
+
+ if (count($rendered) > 1) {
+ // TODO: could we use generic field display ?
+ return theme('content_view_multiple_field', $rendered, $field, $values);
+ }
+ elseif ($rendered) {
+ return $rendered[0];
+ }
+ }
+ }
+
+ return '';
+
+ }
+
+}
+
diff --git a/sites/all/modules/date/date/date_repeat.inc b/sites/all/modules/date/date/date_repeat.inc
new file mode 100644
index 0000000..13f5f94
--- /dev/null
+++ b/sites/all/modules/date/date/date_repeat.inc
@@ -0,0 +1,209 @@
+ 'date_repeat_rrule',
+ '#default_value' => isset($items[0]['rrule']) ? $items[0]['rrule'] : '',
+ '#date_timezone' => $element['#date_timezone'],
+ '#date_format' => date_limit_format(date_input_format($element, $field), $field['granularity']),
+ '#date_text_parts' => (array) $field['widget']['text_parts'],
+ '#date_increment' => $field['widget']['increment'],
+ '#date_year_range' => $field['widget']['year_range'],
+ '#date_label_position' => $field['widget']['label_position'],
+ '#prev_value' => isset($items[0]['value']) ? $items[0]['value'] : '',
+ '#prev_value2' => isset($items[0]['value2']) ? $items[0]['value2'] : '',
+ '#prev_rrule' => isset($items[0]['rrule']) ? $items[0]['rrule'] : '',
+ '#date_repeat_widget' => str_replace('_repeat', '', $field['widget']['type']),
+ '#date_repeat_collapsed' => $field['repeat_collapsed'],
+ );
+
+ return $element;
+}
+/**
+ * Validation for date repeat form element.
+ *
+ * Create multiple values from the RRULE results.
+ * Lots more work needed here.
+ */
+function _date_repeat_widget_validate($element, &$form_state) {
+ require_once('./'. drupal_get_path('module', 'date_repeat') .'/date_repeat_form.inc');
+ $form_values = $form_state['values'];
+ $field_name = $element['#field_name'];
+ $fields = content_fields();
+ $field = $fields[$field_name];
+ $item = $form_values[$field_name];
+ $values = date_repeat_merge($element['#post'][$field_name]['rrule'], $element['rrule']);
+
+ // If no start date was set, clean up the form and return.
+ // If no repeats are set, clean up the form and return.
+ if (empty($form_values[$field_name]['value']) || $values['FREQ'] == 'NONE') {
+ $form_values[$field_name]['rrule'] = NULL;
+ form_set_value($element, array($form_values[$field_name]), $form_state);
+ return;
+ }
+
+ // Require the UNTIL date for now.
+ // The RRULE has already been created by this point, so go back
+ // to the posted values to see if this was filled out.
+ $error_field = implode('][', $element['#parents']) .'][rrule][UNTIL][datetime][date';
+ if (empty($values['UNTIL']['datetime'])) {
+ form_set_error($error_field, t('The UNTIL value is required for repeating dates.'));
+ }
+ if (form_get_errors()) {
+ return;
+ }
+
+ // If the rule, the start date, or the end date have changed, re-calculate
+ // the repeating dates, wipe out the previous values, and populate the
+ // field with the new values.
+
+ // TODO
+ // Is it right to not do anything unless there are changes? Will that
+ // confuse anyone? Commenting that out for now...
+ $rrule = $form_values[$field_name]['rrule'];
+ if (!empty($rrule)
+ //&& ($rrule != $element['rrule']['#prev_rrule']
+ //|| $form_values[$field_name][0]['value'] != $element['rrule']['#prev_value']
+ //|| $form_values[$field_name][0]['value2'] != $element['rrule']['#prev_value2'])
+ ) {
+
+ $item = $form_values[$field_name];
+
+ // Avoid undefined index problems on dates that don't have all parts.
+ $possible_items = array('value', 'value2', 'timezone', 'offset', 'offset2');
+ foreach ($possible_items as $key) {
+ if (empty($item[$key])) {
+ $item[$key] = '';
+ }
+ }
+ $value = date_repeat_build_dates($rrule, $values, $field, $item);
+ form_set_value($element, $value, $form_state);
+ }
+ else {
+ // If no changes are needed, move the RRULE back to the zero value
+ // item of the field.
+ form_set_value(array('#parents' => array($field_name, 0, 'rrule')), $rrule, $form_state);
+ form_set_value($element['rrule'], NULL, $form_state);
+ }
+}
+
+/**
+ * Helper function to build repeating dates from a $node_field.
+ *
+ * Pass in either the RRULE or the $form_values array for the RRULE,
+ * whichever is missing will be created when needed.
+ */
+function date_repeat_build_dates($rrule = NULL, $rrule_values = NULL, $field, $item) {
+ module_load_include('inc', 'date_api', 'date_api_ical');
+ $field_name = $field['field_name'];
+
+ if (empty($rrule)) {
+ $rrule = date_api_ical_build_rrule($rrule_values);
+ }
+ elseif (empty($rrule_values)) {
+ $rrule_values = date_ical_parse_rrule(NULL, $rrule);
+ }
+
+ // By the time we get here, the start and end dates have been
+ // adjusted back to UTC, but we want localtime dates to do
+ // things like '+1 Tuesday', so adjust back to localtime.
+ $timezone = date_get_timezone($field['tz_handling'], $item['timezone']);
+ $timezone_db = date_get_timezone_db($field['tz_handling']);
+ $start = date_make_date($item['value'], $timezone_db, $field['type'], $field['granularity']);
+ if ($timezone != $timezone_db) {
+ date_timezone_set($start, timezone_open($timezone));
+ }
+ if (!empty($item['value2']) && $item['value2'] != $item['value']) {
+ $end = date_make_date($item['value2'], date_get_timezone_db($field['tz_handling']), $field['type'], $field['granularity']);
+ date_timezone_set($end, timezone_open($timezone));
+ }
+ else {
+ $end = $start;
+ }
+ $duration = date_difference($start, $end);
+ $start_datetime = date_format($start, DATE_FORMAT_DATETIME);
+ if (!empty($rrule_values['UNTIL']['datetime'])) {
+ if (strlen($rrule_values['UNTIL']['datetime']) < 11) {
+ $rrule_values['UNTIL']['datetime'] .= ' 23:59:59';
+ }
+ $end = date_ical_date($rrule_values['UNTIL'], $timezone);
+ $end_datetime = date_format($end, DATE_FORMAT_DATETIME);
+ }
+ elseif (!empty($rrule_values['COUNT'])) {
+ $end_datetime = NULL;
+ }
+ else {
+ // No UNTIL and no COUNT?
+ return array();
+ }
+
+ // Split the RRULE into RRULE, EXDATE, and RDATE parts.
+ $parts = date_repeat_split_rrule($rrule);
+ $parsed_exceptions = (array) $parts[1];
+ $exceptions = array();
+ foreach ($parsed_exceptions as $exception) {
+ if (strlen($exception['datetime']) < 11) {
+ $exception['datetime'] .= ' 00:00:00';
+ }
+ $date = date_ical_date($exception, $timezone);
+ $exceptions[] = date_format($date, 'Y-m-d');
+ }
+
+ $parsed_rdates = (array) $parts[2];
+ $additions = array();
+ foreach ($parsed_rdates as $rdate) {
+ if (strlen($rdate['datetime']) < 11) {
+ $rdate['datetime'] .= ' 00:00:00';
+ }
+ $date = date_ical_date($rdate, $timezone);
+ $additions[] = date_format($date, 'Y-m-d');
+ }
+
+ $dates = date_repeat_calc($rrule, $start_datetime, $end_datetime, $exceptions, $timezone, $additions);
+ $value = array();
+ foreach ($dates as $delta => $date) {
+ // date_repeat_calc always returns DATE_DATETIME dates, which is
+ // not necessarily $field['type'] dates.
+ // Convert returned dates back to db timezone before storing.
+ $date_start = date_make_date($date, $timezone, DATE_DATETIME, $field['granularity']);
+ date_timezone_set($date_start, timezone_open($timezone_db));
+ $date_end = drupal_clone($date_start);
+ date_modify($date_end, '+' . $duration . ' seconds');
+ $value[$delta] = array(
+ 'value' => date_format($date_start, date_type_format($field['type'])),
+ 'value2' => date_format($date_end, date_type_format($field['type'])),
+ 'offset' => date_offset_get($date_start),
+ 'offset2' => date_offset_get($date_end),
+ 'timezone' => $timezone,
+ 'rrule' => $rrule,
+ );
+ }
+ return $value;
+}
\ No newline at end of file
diff --git a/sites/all/modules/date/date/date_token.inc b/sites/all/modules/date/date/date_token.inc
new file mode 100644
index 0000000..88158d8
--- /dev/null
+++ b/sites/all/modules/date/date/date_token.inc
@@ -0,0 +1,97 @@
+ $format_info) {
+ $display_text = date_format_date(date_now(), 'custom', $format);
+ $delete_link = l(t('remove'), 'admin/settings/date-time/formats/delete/' . $format_info['dfid']);
+ $row = array($display_text, $delete_link);
+ $rows[] = $row;
+ }
+ $output = theme('table', array(), $rows);
+
+ }
+ else {
+ $output = t('No custom formats configured. Please add some.', array('@link' => url('admin/settings/date-time/formats/add')));
+ }
+
+ return $output;
+}
+
+/**
+ * Allow users to add additional date formats.
+ */
+function date_api_add_date_formats_form($form_state) {
+ // Add date_api.js and js settings.
+ date_api_add_system_javascript();
+
+ $form['add_date_format'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Format string'),
+ '#attributes' => array('class' => 'custom-format'),
+ '#description' => t('A user-defined date format. See the PHP manual for available options. This format is currently set to display as %date.', array('@url' => 'http://php.net/manual/function.date.php', '%date' => date_format_date(date_now(), 'custom', '-'))),
+ );
+
+ $form['update'] = array(
+ '#type' => 'submit',
+ '#value' => t('Save configuration'),
+ '#weight' => 3,
+ '#submit' => array('date_api_date_time_settings_submit'),
+ );
+
+ $form['#validate'][] = 'date_api_date_time_settings_validate';
+
+ return $form;
+}
+
+/**
+ * Add drop down selects for date format types.
+ *
+ * @param &$form
+ * The form being altered.
+ */
+function date_api_date_format_form_elements(&$form) {
+ $form['date_formats'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Date formats'),
+ );
+
+ // Get list of all available date format types.
+ $format_types = date_get_format_types('', TRUE);
+
+ // Get list of all available date formats.
+ $all_formats = array();
+ $date_formats = date_get_formats('', TRUE); // Call this to rebuild the list, and to have default list.
+ foreach ($date_formats as $type => $format_info) {
+ $all_formats = array_merge($all_formats, $format_info);
+ }
+ $custom_formats = date_get_formats('custom');
+ foreach ($format_types as $type => $type_info) {
+ // If a system type, only show the available formats for that type and
+ // custom ones.
+ if ($type_info['locked'] == 1) {
+ $formats = date_get_formats($type);
+ if (empty($formats)) {
+ $formats = $all_formats;
+ }
+ elseif (!empty($custom_formats)) {
+ $formats = array_merge($formats, $custom_formats);
+ }
+ }
+ // If a user configured type, show all available date formats.
+ else {
+ $formats = $all_formats;
+ }
+
+ $choices = array();
+ foreach ($formats as $f => $format) {
+ $choices[$f] = date_format_date(date_now(), 'custom', $f);
+ }
+ $keys = array_keys($formats);
+ $default = variable_get('date_format_' . $type, array_shift($keys));
+
+ // Get format type info for this format type.
+ $type_info = date_get_format_types($type);
+
+ date_api_date_format_select_field($form, $type, $type_info, $default, $choices, 1);
+ }
+}
+
+function date_api_date_time_settings_validate($form, &$form_state) {
+ $formats = date_get_formats('custom');
+ if (!empty($formats) && in_array($form_state['values']['add_date_format'], array_keys($formats))) {
+ form_set_error('add_date_format', t('This format already exists. Please enter a unique format string.'));
+ }
+}
+
+function date_api_date_time_settings_submit($form, &$form_state) {
+ if (!empty($form_state['values']['add_date_format'])) {
+ $format = array();
+ $format['format'] = $form_state['values']['add_date_format'];
+ $format['type'] = 'custom';
+ $format['locked'] = 0;
+ $format['is_new'] = 1;
+ date_format_save($format);
+ }
+
+ // Unset, to prevent this getting saved as a variables.
+ unset($form_state['values']['add_date_format']);
+
+ drupal_set_message(t('Configuration saved.'));
+}
+
+/**
+ * Menu callback; present a form for deleting a date format.
+ */
+function date_api_delete_format_form(&$form_state, $dfid) {
+ $form = array();
+ $form['dfid'] = array(
+ '#type' => 'value',
+ '#value' => $dfid,
+ );
+ $format = date_get_format($dfid);
+
+ $output = confirm_form($form,
+ t('Are you sure you want to remove the format %format?', array('%format' => date_format_date(date_now(), 'custom', $format['format']))),
+ 'admin/settings/date-time/formats/custom',
+ t('This action cannot be undone.'),
+ t('Remove'), t('Cancel'),
+ 'confirm'
+ );
+
+ return $output;
+}
+
+/**
+ * Delete a configured date format.
+ */
+function date_api_delete_format_form_submit($form, &$form_state) {
+ if ($form_state['values']['confirm']) {
+ $format = date_get_format($form_state['values']['dfid']);
+ date_format_delete($form_state['values']['dfid']);
+ drupal_set_message(t('Removed date format %format.', array('%format' => date_format_date(date_now(), 'custom', $format['format']))));
+ $form_state['redirect'] = 'admin/settings/date-time/formats/custom';
+ }
+}
+
+/**
+ * Menu callback; present a form for deleting a date format type.
+ */
+function date_api_delete_format_type_form(&$form_state, $format_type) {
+ $form = array();
+ $form['format_type'] = array(
+ '#type' => 'value',
+ '#value' => $format_type,
+ );
+ $type_info = date_get_format_types($format_type);
+
+ $output = confirm_form($form,
+ t('Are you sure you want to remove the format type %format?', array('%format' => $type_info['title'])),
+ 'admin/settings/date-time/formats',
+ t('This action cannot be undone.'),
+ t('Remove'), t('Cancel'),
+ 'confirm'
+ );
+
+ return $output;
+}
+
+/**
+ * Delete a configured date format type.
+ */
+function date_api_delete_format_type_form_submit($form, &$form_state) {
+ if ($form_state['values']['confirm']) {
+ $type_info = date_get_format_types($form_state['values']['format_type']);
+ date_format_type_delete($form_state['values']['format_type']);
+ drupal_set_message(t('Removed date format type %format.', array('%format' => $type_info['title'])));
+ $form_state['redirect'] = 'admin/settings/date-time/formats';
+ }
+}
+
+/**
+ * Helper function; return form fields for date format selects.
+ */
+function date_api_date_format_select_field(&$form, $type, $type_info, $default, $choices, $show_remove = 0) {
+ // Show date format select list.
+ $form['date_formats']['date_format_' . $type] = array(
+ '#prefix' => '
',
+ // Leave the date-container div open if we are going to be adding to and
+ // then closing it below.
+ '#suffix' => ($show_remove == 1 && $type_info['locked'] == 0) ? '
' : '
',
+ '#type' => 'select',
+ '#title' => t('!type date format', array('!type' => t($type_info['title']))),
+ '#attributes' => array('class' => 'date-format'),
+ '#default_value' => (isset($choices[$default]) ? $default : 'custom'),
+ '#options' => $choices,
+ );
+
+ // If this isn't a system provided type, allow the user to remove it from
+ // the system.
+ if ($show_remove == 1 && $type_info['locked'] == 0) {
+ $form['date_formats']['date_format_' . $type . '_delete'] = array(
+ '#prefix' => '
',
+ '#suffix' => '
',
+ '#value' => l(t('remove'), 'admin/settings/date-time/delete/' . $type),
+ );
+ }
+}
diff --git a/sites/all/modules/date/date_api.info b/sites/all/modules/date/date_api.info
new file mode 100644
index 0000000..f9ae699
--- /dev/null
+++ b/sites/all/modules/date/date_api.info
@@ -0,0 +1,11 @@
+name = Date API
+description = A Date API that can be used by other modules.
+package = Date/Time
+core = 6.x
+
+; Information added by Drupal.org packaging script on 2014-03-31
+version = "6.x-2.10"
+core = "6.x"
+project = "date"
+datestamp = "1396284252"
+
diff --git a/sites/all/modules/date/date_api.install b/sites/all/modules/date/date_api.install
new file mode 100644
index 0000000..53bc5fa
--- /dev/null
+++ b/sites/all/modules/date/date_api.install
@@ -0,0 +1,508 @@
+ 'For storing configured date format types.',
+ 'fields' => array(
+ 'type' => array(
+ 'description' => 'The date format type, e.g. medium.',
+ 'type' => 'varchar',
+ 'length' => 200,
+ 'not null' => TRUE,
+ ),
+ 'title' => array(
+ 'description' => 'The human readable name of the format type.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ ),
+ 'locked' => array(
+ 'description' => 'Whether or not this is a system provided format.',
+ 'type' => 'int',
+ 'size' => 'tiny',
+ 'default' => 0,
+ 'not null' => TRUE,
+ ),
+ ),
+ 'primary key' => array('type'),
+ );
+
+ $schema['date_formats'] = array(
+ 'description' => 'For storing configured date formats.',
+ 'fields' => array(
+ 'dfid' => array(
+ 'description' => 'The date format identifier.',
+ 'type' => 'serial',
+ 'not null' => TRUE,
+ 'unsigned' => TRUE,
+ ),
+ 'format' => array(
+ 'description' => 'The date format string.',
+ 'type' => 'varchar',
+ 'length' => 100,
+ 'not null' => TRUE,
+ ),
+ 'type' => array(
+ 'description' => 'The date format type, e.g. medium.',
+ 'type' => 'varchar',
+ 'length' => 200,
+ 'not null' => TRUE,
+ ),
+ 'locked' => array(
+ 'description' => 'Whether or not this format can be modified.',
+ 'type' => 'int',
+ 'size' => 'tiny',
+ 'default' => 0,
+ 'not null' => TRUE,
+ ),
+ ),
+ 'primary key' => array('dfid'),
+ 'unique keys' => array('formats' => array('format', 'type')),
+ );
+
+ $schema['date_format_locale'] = array(
+ 'description' => 'For storing configured date formats for each locale.',
+ 'fields' => array(
+ 'format' => array(
+ 'description' => 'The date format string.',
+ 'type' => 'varchar',
+ 'length' => 100,
+ 'not null' => TRUE,
+ ),
+ 'type' => array(
+ 'description' => 'The date format type, e.g. medium.',
+ 'type' => 'varchar',
+ 'length' => 200,
+ 'not null' => TRUE,
+ ),
+ 'language' => array(
+ 'description' => 'A {languages}.language for this format to be used with.',
+ 'type' => 'varchar',
+ 'length' => 12,
+ 'not null' => TRUE,
+ ),
+ ),
+ 'primary key' => array('type', 'language'),
+ );
+
+ return $schema;
+}
+
+/**
+ * Implementation of hook_schema_alter(). We alter $schema by reference.
+ *
+ * @param $schema
+ * The system-wide schema collected by drupal_get_schema().
+ */
+function date_api_schema_alter(&$schema) {
+ // Add field to existing schema.
+ $schema['users']['fields']['timezone_name'] = array(
+ 'type' => 'varchar',
+ 'length' => 50,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => t('Per-user timezone name.'),
+ );
+}
+
+/**
+ * Implementation of hook_install().
+ */
+function date_api_install() {
+ drupal_install_schema('date_api');
+
+ // date_api_set_variables can install date_timezone and date_php4. The
+ // date_timezone_install() function does a module_enable('date_api'). This
+ // means that date_api_enable() can be called before date_api_install()
+ // finishes! So the date_api schema needs to be installed before this line!
+ date_api_set_variables();
+
+ $ret = array();
+ db_add_field($ret, "users", "timezone_name", array('type' => 'varchar', 'length' => 50, 'not null' => TRUE, 'default' => ''));
+
+ // Make sure MYSQL does not stupidly do case-insensitive
+ // searches and indexes on our formats.
+ // @see http://pure.rednoize.com/2006/11/26/mysql-collation-matters-when-using-unique-indexes/
+ // @see http://jjinux.blogspot.com/2009/03/mysql-case-sensitivity-hell.html
+ // @see http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html
+ global $db_type;
+ if ($db_type == 'mysql' || $db_type == 'mysqli') {
+ $sql = "ALTER TABLE {date_formats} CHANGE format format VARCHAR( 100 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL";
+ $ret[] = update_sql($sql);
+ $sql = "ALTER TABLE {date_format_locale} CHANGE format format VARCHAR( 100 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL";
+ $ret[] = update_sql($sql);
+ }
+
+ return $ret;
+}
+
+/**
+ * Implementation of hook_enable().
+ */
+function date_api_enable() {
+ // When module is enabled, build the list of date formats and types. This
+ // includes those provided by this module and other contrib modules. As the
+ // date_format tables are created but the schema hasn't been updated, force
+ // a refresh so we can use the schema API.
+ drupal_get_schema('', TRUE);
+ // Ensure schema has been installed - order of things gets out of sync because
+ // date_api_set_variables() in date_api_install() enables the 'date_timezone'
+ // module, which in return enables the 'date_api' module!
+ if (db_table_exists('date_format_types')) {
+ date_formats_rebuild();
+ }
+ date_api_set_variables();
+
+}
+
+/**
+ * Implementation of hook_uninstall().
+ */
+function date_api_uninstall() {
+ $ret = array();
+ db_drop_field($ret, "users", "timezone_name");
+
+ cache_clear_all('date_timezone_identifiers_list', 'cache');
+ $variables = array(
+ 'date_api_version',
+ 'date_min_year',
+ 'date_max_year',
+ 'date_php_min_year',
+ 'date_db_tz_support',
+ 'date_api_use_iso8601',
+ );
+ foreach ($variables as $variable) {
+ variable_del($variable);
+ }
+
+ if (db_table_exists('views_display')) {
+ $displays = array(
+ 'date_nav',
+ );
+ db_query("DELETE FROM {views_display} WHERE display_plugin IN ('". implode("','", $displays) ."')");
+ db_query("DELETE FROM {cache_views}");
+ }
+
+ drupal_uninstall_schema('date_api');
+ return $ret;
+}
+
+/**
+ * Implementation of hook_requirements().
+ * Make sure Date PHP4 is installed if running less than PHP 5.2.
+ */
+function date_api_requirements($phase) {
+ $requirements = array();
+ $t = get_t();
+ switch ($phase) {
+ case 'runtime':
+ $tz_name = variable_get('date_default_timezone_name', NULL);
+ $error = FALSE;
+ if (version_compare(PHP_VERSION, '5.2', '<') && !module_exists('date_php4')) {
+ $error = TRUE;
+ $severity = REQUIREMENT_ERROR;
+ $value = $t('The Date API module requires the Date PHP4 module for PHP versions less than 5.2.', array('@link' => url('admin/build/modules')));
+ }
+ if ($error) {
+ $requirements['date_php4'] = array(
+ 'title' => $t('Date API requirements'),
+ 'value' => $value,
+ 'severity' => $severity,
+ );
+ }
+ break;
+ case 'install':
+ break;
+ }
+ return $requirements;
+}
+
+function date_api_update_last_removed() {
+ return 5201;
+}
+
+/**
+ * Make sure all the appropriate modules get enabled.
+ * Repeated again just to be sure they are set.
+ */
+function date_api_update_6000() {
+ $ret = array();
+ // don't attempt to upgrade if views is not yet upgraded.
+ if (module_exists('views') && drupal_get_installed_schema_version('views', TRUE) < 6000) {
+ $ret = array();
+ drupal_set_message(t('date module cannot be updated until after Views has been updated. Please return to update.php and run the remaining updates.', array('@update-php' => base_path() .'update.php?op=selection')), 'warning', FALSE);
+ $ret['#abort'] = array('success' => FALSE, 'query' => t('date.module has updates, but cannot be updated until views.module is updated first.'));
+
+ return $ret;
+ }
+ date_api_set_variables();
+ return $ret;
+}
+
+/**
+ * Rebuild the theme registry and all the caches.
+ * needed to pick up changes created by updated Views API.
+ */
+function date_api_update_6001() {
+ $ret = array();
+ // don't attempt to upgrade if views is not yet upgraded.
+ if (module_exists('views') && drupal_get_installed_schema_version('views', TRUE) < 6000) {
+ $ret = array();
+ drupal_set_message(t('date module cannot be updated until after Views has been updated. Please return to update.php and run the remaining updates.', array('@update-php' => base_path() .'update.php?op=selection')), 'warning', FALSE);
+ $ret['#abort'] = array('success' => FALSE, 'query' => t('date.module has updates, but cannot be updated until views.module is updated first.'));
+
+ return $ret;
+ }
+ if (db_table_exists('cache_content')) {
+ db_query('DELETE FROM {cache_content}');
+ }
+ if (db_table_exists('cache_views')) {
+ db_query('DELETE FROM {cache_views}');
+ }
+ if (db_table_exists('views_object_cache')) {
+ db_query('DELETE FROM {views_object_cache}');
+ }
+ db_query("DELETE FROM {cache} where cid LIKE 'theme_registry%'");
+ return $ret;
+}
+
+/**
+ * Create new date format tables.
+ */
+function date_api_update_6002() {
+ $ret = array();
+ // don't attempt to upgrade if views is not yet upgraded.
+ if (module_exists('views') && drupal_get_installed_schema_version('views', TRUE) < 6000) {
+ $ret = array();
+ drupal_set_message(t('date module cannot be updated until after Views has been updated. Please return to update.php and run the remaining updates.', array('@update-php' => base_path() .'update.php?op=selection')), 'warning', FALSE);
+ $ret['#abort'] = array('success' => FALSE, 'query' => t('date.module has updates, but cannot be updated until views.module is updated first.'));
+
+ return $ret;
+ }
+
+ $schema['date_format_types'] = array(
+ 'fields' => array(
+ 'type' => array(
+ 'type' => 'varchar',
+ 'length' => 200,
+ 'not null' => TRUE,
+ ),
+ 'title' => array(
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ ),
+ 'locked' => array(
+ 'type' => 'int',
+ 'size' => 'tiny',
+ 'default' => 0,
+ 'not null' => TRUE,
+ ),
+ ),
+ 'primary key' => array('type'),
+ );
+
+ $schema['date_format'] = array(
+ 'fields' => array(
+ 'dfid' => array(
+ 'type' => 'serial',
+ 'not null' => TRUE,
+ 'unsigned' => TRUE,
+ ),
+ 'format' => array(
+ 'type' => 'varchar',
+ 'length' => 100,
+ 'not null' => TRUE,
+ ),
+ 'type' => array(
+ 'type' => 'varchar',
+ 'length' => 200,
+ 'not null' => TRUE,
+ ),
+ 'locked' => array(
+ 'type' => 'int',
+ 'size' => 'tiny',
+ 'default' => 0,
+ 'not null' => TRUE,
+ ),
+ ),
+ 'primary key' => array('dfid'),
+ 'unique keys' => array('format' => array('format', 'type')),
+ );
+
+ $schema['date_format_locale'] = array(
+ 'fields' => array(
+ 'format' => array(
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ ),
+ 'type' => array(
+ 'type' => 'varchar',
+ 'length' => 200,
+ 'not null' => TRUE,
+ ),
+ 'language' => array(
+ 'type' => 'varchar',
+ 'length' => 12,
+ 'not null' => TRUE,
+ ),
+ ),
+ 'primary key' => array('type', 'language'),
+ );
+
+ db_create_table($ret, 'date_format_types', $schema['date_format_types']);
+ db_create_table($ret, 'date_format', $schema['date_format']);
+ db_create_table($ret, 'date_format_locale', $schema['date_format_locale']);
+
+ return $ret;
+}
+
+function date_api_update_6003() {
+ $ret = array();
+ db_change_field($ret, 'date_format_types', 'type', 'type', array('type' => 'varchar', 'length' => 200, 'not null' => TRUE));
+ db_change_field($ret, 'date_format', 'type', 'type', array('type' => 'varchar', 'length' => 200, 'not null' => TRUE));
+ db_change_field($ret, 'date_format', 'format', 'format', array('type' => 'varchar', 'length' => 100, 'not null' => TRUE));
+ db_change_field($ret, 'date_format_locale', 'type', 'type', array('type' => 'varchar', 'length' => 200, 'not null' => TRUE));
+ db_change_field($ret, 'date_format_locale', 'format', 'format', array('type' => 'varchar', 'length' => 100, 'not null' => TRUE));
+ db_drop_unique_key($ret, 'date_format', 'format');
+ db_add_unique_key($ret, 'date_format', 'format', array('format', 'type'));
+ return $ret;
+}
+
+/**
+ * The "date_format" table is missing on boxes having MySQL 5.0.67 installed.
+ * There seems to be a bug in MySQL that prevents the creation of tables with
+ * a name "date_format" and indexes with the name "format".
+ *
+ * We rename the table and index as a workaround.
+ */
+function date_api_update_6004() {
+ $ret = array();
+
+ $schema['date_formats'] = array(
+ 'description' => 'For storing configured date formats.',
+ 'fields' => array(
+ 'dfid' => array(
+ 'description' => 'The date format identifier.',
+ 'type' => 'serial',
+ 'not null' => TRUE,
+ 'unsigned' => TRUE,
+ ),
+ 'format' => array(
+ 'description' => 'The date format string.',
+ 'type' => 'varchar',
+ 'length' => 100,
+ 'not null' => TRUE,
+ ),
+ 'type' => array(
+ 'description' => 'The date format type, e.g. medium.',
+ 'type' => 'varchar',
+ 'length' => 200,
+ 'not null' => TRUE,
+ ),
+ 'locked' => array(
+ 'description' => 'Whether or not this format can be modified.',
+ 'type' => 'int',
+ 'size' => 'tiny',
+ 'default' => 0,
+ 'not null' => TRUE,
+ ),
+ ),
+ 'primary key' => array('dfid'),
+ 'unique keys' => array('formats' => array('format', 'type')),
+ );
+
+ // Create missing table.
+ if (!db_table_exists('date_format')) {
+ db_create_table($ret, 'date_formats', $schema['date_formats']);
+ date_formats_rebuild();
+ }
+ // Rename existing table and index.
+ else {
+ db_drop_unique_key($ret, 'date_format', 'format');
+ if (db_table_exists('date_formats')) {
+ db_drop_table($ret, 'date_format');
+ }
+ else {
+ db_rename_table($ret, 'date_format', 'date_formats');
+ db_add_unique_key($ret, 'date_formats', 'formats', array('format', 'type'));
+ }
+ }
+
+ return $ret;
+}
+
+/**
+ * Make sure MYSQL does not stupidly do case-insensitive
+ * searches and indexes on our formats.
+ * @see http://pure.rednoize.com/2006/11/26/mysql-collation-matters-when-using-unique-indexes/
+ * @see http://jjinux.blogspot.com/2009/03/mysql-case-sensitivity-hell.html
+ * @see http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html
+ */
+function date_api_update_6005() {
+ global $db_type;
+ $ret = array();
+ if ($db_type == 'mysql' || $db_type == 'mysqli') {
+ $sql = "ALTER TABLE {date_formats} CHANGE format format VARCHAR( 100 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL";
+ $ret[] = update_sql($sql);
+ $sql = "ALTER TABLE {date_format_locale} CHANGE format format VARCHAR( 100 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL";
+ $ret[] = update_sql($sql);
+ }
+ return $ret;
+}
+
+/**
+ * Rename the date_format_dfid_seq to date_formats_dfid_seq, as this was missed in 6004
+ * and causes inserts via the UI to fail on PostgreSQL.
+ */
+function date_api_update_6006() {
+ global $db_type;
+ $ret = array();
+ if ($db_type == 'pgsql' && db_table_exists('date_format_dfid_seq')) {
+ $sql = "ALTER TABLE {date_format}_dfid_seq RENAME TO {date_formats}_dfid_seq";
+ $ret[] = update_sql($sql);
+ }
+ return $ret;
+}
diff --git a/sites/all/modules/date/date_api.js b/sites/all/modules/date/date_api.js
new file mode 100644
index 0000000..ee7ffb5
--- /dev/null
+++ b/sites/all/modules/date/date_api.js
@@ -0,0 +1,21 @@
+/**
+ * Show/hide custom format sections on the date-time settings page.
+ */
+Drupal.behaviors.dateDateTime = function(context) {
+ // Show/hide custom format depending on the select's value.
+ $('select.date-format:not(.date-time-processed)', context).change(function() {
+ $(this).addClass('date-time-processed').parents("div.date-container").children("div.custom-container")[$(this).val() == "custom" ? "show" : "hide"]();
+ });
+
+ // Attach keyup handler to custom format inputs.
+ $('input.custom-format:not(.date-time-processed)', context).addClass('date-time-processed').keyup(function() {
+ var input = $(this);
+ var url = Drupal.settings.dateDateTime.lookup +(Drupal.settings.dateDateTime.lookup.match(/\?q=/) ? "&format=" : "?format=") + Drupal.encodeURIComponent(input.val());
+ $.getJSON(url, function(data) {
+ $("div.description span", input.parent()).html(data);
+ });
+ });
+
+ // Trigger the event handler to show the form input if necessary.
+ $('select.date-format', context).trigger('change');
+};
diff --git a/sites/all/modules/date/date_api.module b/sites/all/modules/date/date_api.module
new file mode 100644
index 0000000..3539ab5
--- /dev/null
+++ b/sites/all/modules/date/date_api.module
@@ -0,0 +1,2826 @@
+ 'Formats',
+ 'description' => 'Allow users to configure date formats',
+ 'type' => MENU_LOCAL_TASK,
+ 'file' => 'date_api.admin.inc',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('date_api_date_formats_form'),
+ 'access arguments' => array('administer site configuration'),
+ 'weight' => 1,
+ );
+ $items['admin/settings/date-time/formats/configure'] = array(
+ 'title' => 'Configure',
+ 'description' => 'Allow users to configure date formats',
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ 'file' => 'date_api.admin.inc',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('date_api_date_formats_form'),
+ 'access arguments' => array('administer site configuration'),
+ 'weight' => 1,
+ );
+ $items['admin/settings/date-time/formats/lookup'] = array(
+ 'title' => 'Date and time lookup',
+ 'type' => MENU_CALLBACK,
+ 'page callback' => 'date_api_date_time_lookup',
+ 'access arguments' => array('administer site configuration'),
+ );
+ $items['admin/settings/date-time/formats/custom'] = array(
+ 'title' => 'Custom formats',
+ 'description' => 'Allow users to configure custom date formats.',
+ 'type' => MENU_LOCAL_TASK,
+ 'file' => 'date_api.admin.inc',
+ 'page callback' => 'date_api_configure_custom_date_formats',
+ 'access arguments' => array('administer site configuration'),
+ 'weight' => 2,
+ );
+ $items['admin/settings/date-time/formats/add'] = array(
+ 'title' => 'Add format',
+ 'description' => 'Allow users to add additional date formats.',
+ 'type' => MENU_LOCAL_TASK,
+ 'file' => 'date_api.admin.inc',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('date_api_add_date_formats_form'),
+ 'access arguments' => array('administer site configuration'),
+ 'weight' => 3,
+ );
+ $items['admin/settings/date-time/formats/delete/%'] = array(
+ 'title' => 'Delete date format',
+ 'description' => 'Allow users to delete a configured date format.',
+ 'type' => MENU_CALLBACK,
+ 'file' => 'date_api.admin.inc',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('date_api_delete_format_form', 5),
+ 'access arguments' => array('administer site configuration'),
+ );
+ $items['admin/settings/date-time/delete/%'] = array(
+ 'title' => 'Delete date format type',
+ 'description' => 'Allow users to delete a configured date format type.',
+ 'type' => MENU_CALLBACK,
+ 'file' => 'date_api.admin.inc',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('date_api_delete_format_type_form', 4),
+ 'access arguments' => array('administer site configuration'),
+ );
+
+ return $items;
+}
+
+/**
+ * Implementation of hook_menu_alter().
+ */
+function date_api_menu_alter(&$callbacks) {
+ // Add a new 'admin/settings/date-time/configure' path and make it the same as
+ // the 'admin/settings/date-time'. Also set it to be the default local task -
+ // needed to make tabs work as expected.
+ $callbacks['admin/settings/date-time/configure'] = $callbacks['admin/settings/date-time'];
+ $callbacks['admin/settings/date-time/configure']['type'] = MENU_DEFAULT_LOCAL_TASK;
+}
+
+/**
+ * Helper function for getting the format string for a date type.
+ */
+function date_type_format($type) {
+ switch ($type) {
+ case DATE_ISO:
+ return DATE_FORMAT_ISO;
+ case DATE_UNIX:
+ return DATE_FORMAT_UNIX;
+ case DATE_DATETIME:
+ return DATE_FORMAT_DATETIME;
+ case DATE_ICAL:
+ return DATE_FORMAT_ICAL;
+ }
+}
+
+/**
+ * An untranslated array of month names
+ *
+ * Needed for css, translation functions, strtotime(), and other places
+ * that use the English versions of these words.
+ *
+ * @return
+ * an array of month names
+ */
+function date_month_names_untranslated() {
+ static $month_names;
+ if (empty($month_names)) {
+ $month_names = array(1 => 'January', 2 => 'February', 3 => 'March',
+ 4 => 'April', 5 => 'May', 6 => 'June', 7 => 'July',
+ 8 => 'August', 9 => 'September', 10 => 'October',
+ 11 => 'November', 12 => 'December');
+ }
+ return $month_names;
+}
+
+/**
+ * A translated array of month names
+ *
+ * @param $required
+ * If not required, will include a blank value at the beginning of the list.
+ * @return
+ * an array of month names
+ */
+function date_month_names($required = FALSE) {
+ $month_names = array();
+ foreach (date_month_names_untranslated() as $key => $day) {
+ $month_names[$key] = date_t($day, 'month_name');
+ }
+ $none = array('' => '');
+ return !$required ? $none + $month_names : $month_names;
+}
+
+/**
+ * A translated array of month name abbreviations
+ *
+ * @param $required
+ * If not required, will include a blank value at the beginning of the list.
+ * @return
+ * an array of month abbreviations
+ */
+function date_month_names_abbr($required = FALSE) {
+ $month_names = array();
+ foreach (date_month_names_untranslated() as $key => $day) {
+ $month_names[$key] = date_t($day, 'month_abbr');
+ }
+ $none = array('' => '');
+ return !$required ? $none + $month_names : $month_names;
+}
+
+/**
+ * An untranslated array of week days
+ *
+ * Needed for css, translation functions, strtotime(), and other places
+ * that use the English versions of these words.
+ *
+ * @return
+ * an array of week day names
+ */
+function date_week_days_untranslated($refresh = TRUE) {
+ static $weekdays;
+ if ($refresh || empty($weekdays)) {
+ $weekdays = array(0 => 'Sunday', 1 => 'Monday', 2 => 'Tuesday',
+ 3 => 'Wednesday', 4 => 'Thursday', 5 => 'Friday',
+ 6 => 'Saturday');
+ }
+ return $weekdays;
+}
+
+/**
+ * A translated array of week days
+ *
+ * @param $required
+ * If not required, will include a blank value at the beginning of the array.
+ * @return
+ * an array of week day names
+ */
+function date_week_days($required = FALSE, $refresh = TRUE) {
+ $weekdays = array();
+ foreach (date_week_days_untranslated() as $key => $day) {
+ $weekdays[$key] = date_t($day, 'day_name');
+ }
+ $none = array('' => '');
+ return !$required ? $none + $weekdays : $weekdays;
+}
+
+/**
+ * An translated array of week day abbreviations.
+ *
+ * @param $required
+ * If not required, will include a blank value at the beginning of the array.
+ * @return
+ * an array of week day abbreviations
+ */
+function date_week_days_abbr($required = FALSE, $refresh = TRUE, $length = 3) {
+ $weekdays = array();
+ switch ($length) {
+ case 1:
+ $context = 'day_abbr1';
+ break;
+ case 2:
+ $context = 'day_abbr2';
+ break;
+ default:
+ $context = 'day_abbr';
+ break;
+ }
+ foreach (date_week_days_untranslated() as $key => $day) {
+ $weekdays[$key] = date_t($day, $context);
+ }
+ $none = array('' => '');
+ return !$required ? $none + $weekdays : $weekdays;
+}
+
+/**
+ * Order weekdays
+ * Correct weekdays array so first day in array matches the first day of
+ * the week. Use to create things like calendar headers.
+ *
+ * @param array $weekdays
+ * @return array
+ */
+function date_week_days_ordered($weekdays) {
+ if (variable_get('date_first_day', 1) > 0) {
+ for ($i = 1; $i <= variable_get('date_first_day', 1); $i++) {
+ $last = array_shift($weekdays);
+ array_push($weekdays, $last);
+ }
+ }
+ return $weekdays;
+}
+
+/**
+ * An array of years.
+ *
+ * @param int $min
+ * the minimum year in the array
+ * @param int $max
+ * the maximum year in the array
+ * @param $required
+ * If not required, will include a blank value at the beginning of the array.
+ * @return
+ * an array of years in the selected range
+ */
+function date_years($min = 0, $max = 0, $required = FALSE) {
+ // Have to be sure $min and $max are valid values;
+ if (empty($min)) $min = intval(date('Y', time()) - 3);
+ if (empty($max)) $max = intval(date('Y', time()) + 3);
+ $none = array(0 => '');
+ return !$required ? $none + drupal_map_assoc(range($min, $max)) : drupal_map_assoc(range($min, $max));
+}
+
+/**
+ * An array of days.
+ *
+ * @param $required
+ * If not required, returned array will include a blank value.
+ * @param integer $month (optional)
+ * @param integer $year (optional)
+ * @return
+ * an array of days for the selected month.
+ */
+function date_days($required = FALSE, $month = NULL, $year = NULL) {
+ // If we have a month and year, find the right last day of the month.
+ if (!empty($month) && !empty($year)) {
+ $date = date_make_date($year .'-'. $month .'-01 00:00:00', 'UTC');
+ $max = date_format('t', $date);
+ }
+ // If there is no month and year given, default to 31.
+ if (empty($max)) $max = 31;
+ $none = array(0 => '');
+ return !$required ? $none + drupal_map_assoc(range(1, $max)) : drupal_map_assoc(range(1, $max));
+}
+
+/**
+ * An array of hours.
+ *
+ * @param string $format
+ * @param $required
+ * If not required, returned array will include a blank value.
+ * @return
+ * an array of hours in the selected format.
+ */
+function date_hours($format = 'H', $required = FALSE) {
+ $hours = array();
+ if ($format == 'h' || $format == 'g') {
+ $min = 1;
+ $max = 12;
+ }
+ else {
+ $min = 0;
+ $max = 23;
+ }
+ for ($i = $min; $i <= $max; $i++) {
+ $hours[$i] = $i < 10 && ($format == 'H' || $format == 'h') ? "0$i" : $i;
+ }
+ $none = array('' => '');
+ return !$required ? $none + $hours : $hours;
+}
+
+/**
+ * An array of minutes.
+ *
+ * @param string $format
+ * @param $required
+ * If not required, returned array will include a blank value.
+ * @return
+ * an array of minutes in the selected format.
+ */
+function date_minutes($format = 'i', $required = FALSE, $increment = 1) {
+ $minutes = array();
+ // Have to be sure $increment has a value so we don't loop endlessly;
+ if (empty($increment)) $increment = 1;
+ for ($i = 0; $i < 60; $i += $increment) {
+ $minutes[$i] = $i < 10 && $format == 'i' ? "0$i" : $i;
+ }
+ $none = array('' => '');
+ return !$required ? $none + $minutes : $minutes;
+}
+
+/**
+ * An array of seconds.
+ *
+ * @param string $format
+ * @param $required
+ * If not required, returned array will include a blank value.
+ * @return array an array of seconds in the selected format.
+ */
+function date_seconds($format = 's', $required = FALSE, $increment = 1) {
+ $seconds = array();
+ // Have to be sure $increment has a value so we don't loop endlessly;
+ if (empty($increment)) $increment = 1;
+ for ($i = 0; $i < 60; $i += $increment) {
+ $seconds[$i] = $i < 10 && $format == 's' ? "0$i" : $i;
+ }
+ $none = array('' => '');
+ return !$required ? $none + $seconds : $seconds;
+}
+
+/**
+ * An array of am and pm options.
+ * @param $required
+ * If not required, returned array will include a blank value.
+ * @return array an array of am pm options.
+ */
+function date_ampm($required = FALSE) {
+ $none = array('' => '');
+ $ampm = array('am' => date_t('am', 'ampm'), 'pm' => date_t('pm', 'ampm'));
+ return !$required ? $none + $ampm : $ampm;
+}
+
+/**
+ * Implementation of hook_date_formats().
+ *
+ * @return
+ * An array of date formats with attributes 'type' (short, medium or long),
+ * 'format' (the format string) and 'locales'. The 'locales' attribute is an
+ * array of locales, which can include both 2 character language codes like
+ * 'en', 'fr', but also 5 character language codes like 'en-gb' and 'en-us'.
+ */
+function date_api_date_formats() {
+ include_once('./'. drupal_get_path('module', 'date_api') .'/date_api_formats_list.inc');
+ return _date_api_date_formats_list();
+}
+
+/**
+ * Implementation of hook_date_format_types().
+ */
+function date_api_date_format_types() {
+ return array(
+ 'long' => t('Long'),
+ 'medium' => t('Medium'),
+ 'short' => t('Short'),
+ );
+}
+
+/**
+ * Array of regex replacement strings for date format elements.
+ * Used to allow input in custom formats. Based on work done for
+ * the Date module by Yves Chedemois (yched).
+ *
+ * @return array of date() format letters and their regex equivalents.
+ */
+function date_format_patterns($strict = FALSE) {
+ return array(
+ 'd' => '\d{'. ($strict ? '2' : '1,2') .'}',
+ 'm' => '\d{'. ($strict ? '2' : '1,2') .'}',
+ 'h' => '\d{'. ($strict ? '2' : '1,2') .'}',
+ 'H' => '\d{'. ($strict ? '2' : '1,2') .'}',
+ 'i' => '\d{'. ($strict ? '2' : '1,2') .'}',
+ 's' => '\d{'. ($strict ? '2' : '1,2') .'}',
+ 'j' => '\d{1,2}', 'N' => '\d', 'S' => '\w{2}',
+ 'w' => '\d', 'z' => '\d{1,3}', 'W' => '\d{1,2}',
+ 'n' => '\d{1,2}', 't' => '\d{2}', 'L' => '\d', 'o' => '\d{4}',
+ 'Y' => '\d{4}', 'y' => '\d{2}', 'B' => '\d{3}', 'g' => '\d{1,2}',
+ 'G' => '\d{1,2}', 'e' => '\w*', 'I' => '\d', 'T' => '\w*',
+ 'U' => '\d*', 'z' => '[+-]?\d*', 'O' => '[+-]?\d{4}',
+ //Using S instead of w and 3 as well as 4 to pick up non-ASCII chars like German umlaute.
+ // Per http://drupal.org/node/1101294, we may need as little as 2 and as many as 5 characters
+ // in some languages.
+ 'D' => '\S{2,5}', 'l' => '\S*', 'M' => '\S{2,5}', 'F' => '\S*',
+ 'P' => '[+-]?\d{2}\:\d{2}',
+ 'c' => '(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})([+-]?\d{2}\:\d{2})',
+ 'r' => '(\w{3}), (\d{2})\s(\w{3})\s(\d{2,4})\s(\d{2}):(\d{2}):(\d{2})([+-]?\d{4})?',
+ );
+}
+
+/**
+ * Array of granularity options and their labels
+ *
+ * @return array
+ */
+function date_granularity_names() {
+ return array(
+ 'year' => date_t('Year', 'datetime'),
+ 'month' => date_t('Month', 'datetime'),
+ 'day' => date_t('Day', 'datetime'),
+ 'hour' => date_t('Hour', 'datetime'),
+ 'minute' => date_t('Minute', 'datetime'),
+ 'second' => date_t('Second', 'datetime'),
+ );
+}
+
+/**
+ * Sort a granularity array.
+ */
+function date_granularity_sorted($granularity) {
+ return array_intersect(array('year', 'month', 'day', 'hour', 'minute', 'second'), $granularity);
+}
+
+/**
+ * Give a granularity $precision, return an array of
+ * all the possible granularity elements.
+ */
+function date_granularity_array_from_precision($precision) {
+ $granularity_array = array('year', 'month', 'day', 'hour', 'minute', 'second');
+ switch (($precision)) {
+ case 'year':
+ return array_slice($granularity_array, -6);
+ case 'month':
+ return array_slice($granularity_array, -5);
+ case 'day':
+ return array_slice($granularity_array, -4);
+ case 'hour':
+ return array_slice($granularity_array, -3);
+ case 'minute':
+ return array_slice($granularity_array, -2);
+ default:
+ return $granularity_array;
+ }
+}
+
+/**
+ * Give a granularity array, return the highest precision.
+ */
+function date_granularity_precision($granularity_array) {
+ $input = date_granularity_sorted($granularity_array);
+ return array_pop($input);
+}
+
+/**
+ * Construct an appropriate DATETIME format string for the granularity of an item.
+ */
+function date_granularity_format($granularity) {
+ if (is_array($granularity)) {
+ $granularity = date_granularity_precision($granularity);
+ }
+ $format = 'Y-m-d H:i:s';
+ switch ($granularity) {
+ case 'year':
+ return drupal_substr($format, 0, 1);
+ case 'month':
+ return drupal_substr($format, 0, 3);
+ case 'day':
+ return drupal_substr($format, 0, 5);
+ case 'hour';
+ return drupal_substr($format, 0, 7);
+ case 'minute':
+ return drupal_substr($format, 0, 9);
+ default:
+ return $format;
+ }
+}
+
+/**
+ * A translated array of timezone names.
+ * Cache the untranslated array, make the translated array a static variable.
+ *
+ * @param $required
+ * If not required, returned array will include a blank value.
+ * @return
+ * an array of timezone names
+ */
+function date_timezone_names($required = FALSE, $refresh = FALSE) {
+ static $zonenames;
+ if (empty($zonenames) || $refresh) {
+ $cached = cache_get('date_timezone_identifiers_list');
+ $zonenames = !empty($cached) ? $cached->data : array();
+ if ($refresh || empty($cached) || empty($zonenames)) {
+ $data = timezone_identifiers_list();
+ asort($data);
+ // Use include instead of include once in case the function gets
+ // refreshed via devel or other API and is called more than once.
+ if (module_exists('date_php4')) {
+ include('./'. drupal_get_path('module', 'date_php4') .'/date_php4_missing_data.inc');
+ }
+ foreach ($data as $delta => $zone) {
+ // Because many time zones exist in PHP only for backward
+ // compatibility reasons and should not be used, the list is
+ // filtered by a regular expression.
+ if (preg_match('!^((Africa|America|Antarctica|Arctic|Asia|Atlantic|Australia|Europe|Indian|Pacific)/|UTC$)!', $zone)) {
+ $zonenames[$zone] = $zone;
+ }
+ }
+ // If using PHP4, filter the list down to only the timezones
+ // the PHP4 wrapper has data for.
+ if (module_exists('date_php4')) {
+ foreach ($missing_timezone_data as $zone) {
+ unset($zonenames[$zone]);
+ }
+ }
+
+ // If using Event, further filter the list down to only
+ // zones that exist in the event module.
+ if (module_exists('event') && db_table_exists('event_timezones')) {
+ $result = db_query("SELECT name FROM {event_timezones} ORDER BY name");
+ $names = array();
+ while ($row = db_fetch_array($result)) {
+ $names[] = str_replace(' ', '_', $row['name']);
+ }
+ foreach ($zonenames as $name => $zone) {
+ if (!in_array($name, $names)) {
+ unset($zonenames[$name]);
+ }
+ }
+ }
+ if (!empty($zonenames)) {
+ cache_set('date_timezone_identifiers_list', $zonenames);
+ }
+ }
+ foreach ($zonenames as $zone) {
+ $zonenames[$zone] = t('!timezone', array('!timezone' => t($zone)));
+ }
+ }
+ $none = array('' => '');
+ return !$required ? $none + $zonenames : $zonenames;
+}
+
+/**
+ * An array of timezone abbreviations that the system allows.
+ * Cache an array of just the abbreviation names because the
+ * whole timezone_abbreviations_list is huge so we don't want
+ * to get it more than necessary.
+ *
+ * @return array
+ */
+function date_timezone_abbr($refresh = FALSE) {
+ $cached = cache_get('date_timezone_abbreviations');
+ $data = isset($cached->data) ? $cached->data : array();
+ if (empty($data) || $refresh) {
+ $data = array_keys(timezone_abbreviations_list());
+ cache_set('date_timezone_abbreviations', $data);
+ }
+ return $data;
+}
+
+/**
+ * A function to translate ambiguous short date strings.
+ *
+ * Example: Pass in 'Monday', 'day_abbr' and get the translated
+ * abbreviation for Monday.
+ *
+ * @param string $string
+ * @param string $context
+ * @param int $langcode
+ * @return translated value of the string
+ */
+function date_t($string, $context, $langcode = NULL) {
+ static $replace = array();
+
+ if (empty($replace[$langcode])) {
+ // The function to create the date string arrays is kept separate
+ // so those arrays can be directly accessed by other functions.
+ date_t_strings($replace, $langcode);
+ }
+ switch ($context) {
+ case 'day_name':
+ case 'day_abbr':
+ case 'day_abbr1':
+ case 'day_abbr2':
+ $untranslated = array_flip(date_week_days_untranslated());
+ break;
+ case 'month_name':
+ case 'month_abbr':
+ $untranslated = array_flip(date_month_names_untranslated());
+ break;
+ case 'ampm':
+ $untranslated = array_flip(array('am', 'pm', 'AM', 'PM'));
+ break;
+ case 'datetime':
+ $untranslated = array_flip(array('Year', 'Month', 'Day', 'Week', 'Hour', 'Minute', 'Second', 'All Day', 'All day'));
+ break;
+ case 'datetime_plural':
+ $untranslated = array_flip(array('Years', 'Months', 'Days', 'Weeks', 'Hours', 'Minutes', 'Seconds'));
+ break;
+ case 'date_order':
+ $untranslated = array_flip(array('Every', 'First', 'Second', 'Third', 'Fourth', 'Fifth'));
+ break;
+ case 'date_order_reverse':
+ $untranslated = array_flip(array('', 'Last', 'Next to last', 'Third from last', 'Fourth from last', 'Fifth from last'));
+ break;
+ case 'date_nav':
+ $untranslated = array_flip(array('Prev', 'Next', 'Today'));
+ break;
+ }
+ $pos = $untranslated[$string];
+ return $replace[$langcode][$context][$pos];
+}
+
+/**
+ * Construct translation arrays from pipe-delimited strings.
+ *
+ * Combining these strings into a single t() gives them the context needed
+ * for better translation.
+ */
+function date_t_strings(&$replace, $langcode) {
+ $replace[$langcode]['day_name'] = explode('|', trim(t('!day-name Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday', array('!day-name' => ''), $langcode)));
+ $replace[$langcode]['day_abbr'] = explode('|', trim(t('!day-abbreviation Sun|Mon|Tue|Wed|Thu|Fri|Sat', array('!day-abbreviation' => ''), $langcode)));
+ $replace[$langcode]['day_abbr1'] = explode('|', trim(t('!day-abbreviation S|M|T|W|T|F|S', array('!day-abbreviation' => ''), $langcode)));
+ $replace[$langcode]['day_abbr2'] = explode('|', trim(t('!day-abbreviation SU|MO|TU|WE|TH|FR|SA', array('!day-abbreviation' => ''), $langcode)));
+ $replace[$langcode]['ampm'] = explode('|', trim(t('!ampm-abbreviation am|pm|AM|PM', array('!ampm-abbreviation' => ''), $langcode)));
+ $replace[$langcode]['datetime'] = explode('|', trim(t('!datetime Year|Month|Day|Week|Hour|Minute|Second|All Day|All day', array('!datetime' => ''), $langcode)));
+ $replace[$langcode]['datetime_plural'] = explode('|', trim(t('!datetime_plural Years|Months|Days|Weeks|Hours|Minutes|Seconds', array('!datetime_plural' => ''), $langcode)));
+ $replace[$langcode]['date_order'] = explode('|', trim(t('!date_order Every|First|Second|Third|Fourth|Fifth', array('!date_order' => ''), $langcode)));
+ $replace[$langcode]['date_order_reverse'] = explode('|', trim(t('!date_order |Last|Next to last|Third from last|Fourth from last|Fifth from last', array('!date_order' => ''), $langcode)));
+ $replace[$langcode]['date_nav'] = explode('|', trim(t('!date_nav Prev|Next|Today', array('!date_nav' => ''), $langcode)));
+
+ // These start with a pipe so the January value will be in position 1 instead of position 0.
+ $replace[$langcode]['month_name'] = explode('|', trim(t('!month-name |January|February|March|April|May|June|July|August|September|October|November|December', array('!month-name' => ''), $langcode)));
+ $replace[$langcode]['month_abbr'] = explode('|', trim(t('!month-abbreviation |Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec', array('!month-abbreviation' => ''), $langcode)));
+}
+
+/**
+ * Reworked from Drupal's format_date function to handle pre-1970 and
+ * post-2038 dates and accept a date object instead of a timestamp as input.
+ *
+ * Translates formatted date results, unlike PHP function date_format().
+ *
+ * @param $date
+ * A date object, could be created by date_make_date().
+ * @param $type
+ * The format to use. Can be "small", "medium" or "large" for the preconfigured
+ * date formats. If "custom" is specified, then $format is required as well.
+ * @param $format
+ * A PHP date format string as required by date(). A backslash should be used
+ * before a character to avoid interpreting the character as part of a date
+ * format.
+ * @return
+ * A translated date string in the requested format.
+ */
+function date_format_date($date, $type = 'medium', $format = '', $langcode = NULL) {
+ if (empty($date)) {
+ return '';
+ }
+
+ if (function_exists('timezone_name_from_abbr') && get_class($date) != 'DateTime') {
+ $date = date_make_date($date);
+ }
+ switch ($type) {
+ case 'small':
+ case 'short':
+ $format = variable_get('date_format_short', 'm/d/Y - H:i');
+ break;
+ case 'large':
+ case 'long':
+ $format = variable_get('date_format_long', 'l, F j, Y - H:i');
+ break;
+ case 'custom':
+ $format = $format;
+ break;
+ case 'medium':
+ default:
+ $format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
+ }
+ $max = drupal_strlen($format);
+ $datestring = '';
+ for ($i = 0; $i < $max; $i++) {
+ $c = $format[$i];
+ switch ($c) {
+ // Use date_t() for ambiguous short strings that need translation.
+ // We send long day and month names to date_t(), along with context.
+ case 'l':
+ $datestring .= date_t(date_format($date, 'l'), 'day_name', $langcode);
+ break;
+ case 'D':
+ $datestring .= date_t(date_format($date, 'l'), 'day_abbr', $langcode);
+ break;
+ case 'F':
+ $datestring .= date_t(date_format($date, 'F'), 'month_name', $langcode);
+ break;
+ case 'M':
+ $datestring .= date_t(date_format($date, 'F'), 'month_abbr', $langcode);
+ break;
+ case 'A':
+ case 'a':
+ $datestring .= date_t(date_format($date, $c), 'ampm', $langcode);
+ break;
+ // The timezone name translations can use t().
+ case 'e':
+ case 'T':
+ $datestring .= t(date_format($date, $c));
+ break;
+ // Remaining date parts need no translation.
+ case 'O':
+ $datestring .= sprintf('%s%02d%02d', (date_offset_get($date) < 0 ? '-' : '+'), abs(date_offset_get($date) / 3600), abs(date_offset_get($date) % 3600) / 60);
+ break;
+ case 'P':
+ $datestring .= sprintf('%s%02d:%02d', (date_offset_get($date) < 0 ? '-' : '+'), abs(date_offset_get($date) / 3600), abs(date_offset_get($date) % 3600) / 60);
+ break;
+ case 'Z':
+ $datestring .= date_offset_get($date);
+ break;
+ case '\\':
+ $datestring .= $format[++$i];
+ break;
+ case 'r':
+ $datestring .= date_format_date($date, 'custom', 'D, d M Y H:i:s O', $langcode);
+ break;
+ default:
+ if (strpos('BdcgGhHiIjLmnNosStTuUwWYyz', $c) !== FALSE) {
+ $datestring .= date_format($date, $c);
+ }
+ else {
+ $datestring .= $c;
+ }
+ }
+ }
+ return $datestring;
+}
+
+/**
+ * An override for interval formatting that adds past and future context
+ *
+ * @param DateTime $date
+ * @param integer $granularity
+ * @return formatted string
+ */
+function date_format_interval($date, $granularity = 2) {
+ // If no date is sent, then return nothing
+ if (empty($date)) {
+ return NULL;
+ }
+
+ $interval = time() - date_format($date, 'U');
+ if ($interval > 0 ) {
+ return t('!time ago', array('!time' => format_interval($interval, $granularity)));
+ }
+ else {
+ return format_interval(abs($interval), $granularity);
+ }
+}
+
+/**
+ * A date object for the current time.
+ *
+ * @param $timezone
+ * Optional method to force time to a specific timezone,
+ * defaults to user timezone, if set, otherwise site timezone.
+ * @return object date
+ */
+function date_now($timezone = NULL) {
+ return date_make_date('now', $timezone);
+}
+
+/**
+ * Convert a date of any type or an array of date parts into a valid date
+ * object.
+
+ * @param $date
+ * A date in any format or the string 'now'.
+ * @param $timezone
+ * Optional, the name of the timezone this date is in, defaults
+ * to the user timezone, if set, otherwise the site timezone.
+ * Accepts either a timezone name or a timezone object as input.
+ * @param $type
+ * The type of date provided, could be
+ * DATE_ARRAY, DATE_UNIX, DATE_DATETIME, DATE_ISO, or DATE_OBJECT.
+ * @param $granularity
+ * The granularity of the date value provided. Set this for partial
+ * dates so they pass validation and don't get reset to 'now'.
+ */
+function date_make_date($date, $timezone = NULL, $type = DATE_DATETIME, $granularity = array('year', 'month', 'day', 'hour', 'minute')) {
+
+ // Make sure some value is set for the date and timezone even if the
+ // site timezone is not yet set up to avoid fatal installation
+ // errors.
+ if (empty($timezone) || !date_timezone_is_valid($timezone)) {
+ $timezone = date_default_timezone_name();
+ }
+
+ // Special handling for a unix timestamp of '0', since it will fail 'empty' tests below.
+ if ($date === 0 && $type == DATE_UNIX) {
+ $date = date_convert($date, $type, DATE_DATETIME, $timezone);
+ $type = DATE_DATETIME;
+ }
+
+ // No value or one with unexpected array keys.
+ if (empty($date) || (is_array($date) && array_diff($granularity, array_keys($date)))) {
+ return NULL;
+ }
+
+ // Special handling for partial dates that don't need precision.
+ $granularity_sorted = date_granularity_sorted($granularity);
+ $max_granularity = end($granularity_sorted);
+ if (in_array($max_granularity, array('year', 'month')) || $type == DATE_ISO || $type == DATE_ARRAY) {
+ if ($type == DATE_UNIX) {
+ $date = date_convert($date, $type, DATE_DATETIME);
+ }
+ $date = date_fuzzy_datetime($date);
+ $type = DATE_DATETIME;
+ }
+
+ if (!date_is_valid($date, $type, $granularity)) {
+ $date = 'now';
+ }
+ if (!empty($timezone) && !empty($date)) {
+ if ($date == 'now') {
+ return date_create('now', timezone_open($timezone));
+ }
+ elseif ($datetime = date_convert($date, $type, DATE_DATETIME, $timezone)) {
+ return date_create($datetime, timezone_open($timezone));
+ }
+ }
+ return NULL;
+}
+
+function date_timezone_is_valid($timezone) {
+ static $timezone_names;
+ if (empty($timezone_names)) {
+ $timezone_names = array_keys(date_timezone_names(TRUE));
+ }
+ if (!in_array($timezone, $timezone_names)) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Return a timezone name to use as a default.
+ *
+ * @return a timezone name
+ * Identify the default timezone for a user, if available, otherwise the site.
+ * Must return a value even if no timezone info has been set up.
+ */
+function date_default_timezone_name($check_user = TRUE) {
+ global $user;
+ if ($check_user && variable_get('configurable_timezones', 1) && !empty($user->timezone_name)) {
+ return $user->timezone_name;
+ }
+ else {
+ $default = variable_get('date_default_timezone_name', '');
+ return empty($default) ? 'UTC' : $default;
+ }
+}
+
+/**
+ * A timezone object for the default timezone.
+ *
+ * @return a timezone object
+ * Identify the default timezone for a user, if available, otherwise the site.
+ */
+function date_default_timezone($check_user = TRUE) {
+ $timezone = date_default_timezone_name($check_user);
+ return timezone_open(date_default_timezone_name($check_user));
+}
+
+/**
+ * Identify the number of days in a month for a date.
+ */
+function date_days_in_month($year, $month) {
+ // Pick a day in the middle of the month to avoid timezone shifts.
+ $datetime = date_pad($year, 4) .'-'. date_pad($month) .'-15 00:00:00';
+ $date = date_make_date($datetime);
+ return date_format($date, 't');
+}
+
+/**
+ * Identify the number of days in a year for a date.
+ *
+ * @param mixed $date
+ * @param string $type
+ * @return integer
+ */
+function date_days_in_year($date = NULL, $type = DATE_OBJECT) {
+ if (empty($date)) {
+ $date = date_now();
+ }
+ if (!is_object($date)) {
+ $date = date_convert($date, $type, DATE_OBJECT);
+ }
+ if (is_object($date)) {
+ if (date_format($date, 'L')) {
+ return 366;
+ }
+ else {
+ return 365;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Identify the number of ISO weeks in a year for a date.
+ *
+ * December 28 is always in the last ISO week of the year.
+ *
+ * @param mixed $date
+ * @param string $type
+ * @return integer
+ */
+function date_iso_weeks_in_year($date = NULL, $type = DATE_OBJECT) {
+ if (empty($date)) {
+ $date = date_now();
+ }
+ if (!is_object($date)) {
+ $date = date_convert($date, $type, DATE_OBJECT);
+ }
+ if (is_object($date)) {
+ date_date_set($date, date_format($date, 'Y'), 12, 28);
+ return date_format($date, 'W');
+ }
+ return NULL;
+}
+
+/**
+ * Returns day of week for a given date (0 = Sunday).
+ *
+ * @param mixed $date
+ * a date, default is current local day
+ * @param string $type
+ * The type of date, DATE_ISO, DATE_DATETIME, or DATE_UNIX
+ * @return
+ * the number of the day in the week
+ */
+function date_day_of_week($date = NULL, $type = DATE_OBJECT) {
+ if (empty($date)) {
+ $date = date_now();
+ $type = DATE_OBJECT;
+ }
+ $date = date_convert($date, $type, DATE_OBJECT);
+ if (is_object($date)) {
+ return date_format($date, 'w');
+ }
+ return NULL;
+}
+
+/**
+ * Returns translated name of the day of week for a given date.
+ *
+ * @param mixed $date
+ * a date, default is current local day
+ * @param string $type
+ * The type of date, DATE_ISO, DATE_DATETIME, or DATE_UNIX
+ * @param string $abbr
+ * Whether to return the abbreviated name for that day
+ * @return
+ * the name of the day in the week for that date
+ */
+function date_day_of_week_name($date = NULL, $abbr = TRUE, $type = DATE_DATETIME) {
+ $dow = date_day_of_week($date, $type);
+ $days = $abbr ? date_week_days_abbr() : date_week_days();
+ return $days[$dow];
+}
+
+/**
+ * Compute difference between two days using a given measure.
+ *
+ * @param mixed $date1
+ * the starting date
+ * @param mixed $date2
+ * the ending date
+ * @param string $measure
+ * 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds'
+ * @param string $type
+ * the type of dates provided:
+ * DATE_OBJECT, DATE_DATETIME, DATE_ISO, DATE_UNIX, DATE_ARRAY
+ */
+function date_difference($date1_in, $date2_in, $measure = 'seconds', $type = DATE_OBJECT) {
+ // Create cloned objects or original dates will be impacted by
+ // the date_modify() operations done in this code.
+ $date1 = drupal_clone(date_convert($date1_in, $type, DATE_OBJECT));
+ $date2 = drupal_clone(date_convert($date2_in, $type, DATE_OBJECT));
+ if (is_object($date1) && is_object($date2)) {
+ $diff = date_format($date2, 'U') - date_format($date1, 'U');
+ if ($diff == 0 ) {
+ return 0;
+ }
+ elseif ($diff < 0) {
+ // Make sure $date1 is the smaller date.
+ $temp = $date2;
+ $date2 = $date1;
+ $date1 = $temp;
+ $diff = date_format($date2, 'U') - date_format($date1, 'U');
+ }
+ $year_diff = intval(date_format($date2, 'Y') - date_format($date1, 'Y'));
+ switch ($measure) {
+
+ // The easy cases first.
+ case 'seconds':
+ return $diff;
+ case 'minutes':
+ return $diff / 60;
+ case 'hours':
+ return $diff / 3600;
+ case 'years':
+ return $year_diff;
+
+ case 'months':
+ $format = 'n';
+ $item1 = date_format($date1, $format);
+ $item2 = date_format($date2, $format);
+ if ($year_diff == 0) {
+ return intval($item2 - $item1);
+ }
+ else {
+ $item_diff = 12 - $item1;
+ $item_diff += intval(($year_diff - 1) * 12);
+ return $item_diff + $item2;
+ }
+ break;
+
+ case 'days':
+ $format = 'z';
+ $item1 = date_format($date1, $format);
+ $item2 = date_format($date2, $format);
+ if ($year_diff == 0) {
+ return intval($item2 - $item1);
+ }
+ else {
+ $item_diff = date_days_in_year($date1) - $item1;
+ for ($i = 1; $i < $year_diff; $i++) {
+ date_modify($date1, '+1 year');
+ $item_diff += date_days_in_year($date1);
+ }
+ return $item_diff + $item2;
+ }
+ break;
+
+ case 'weeks':
+ $week_diff = date_format($date2, 'W') - date_format($date1, 'W');
+ $year_diff = date_format($date2, 'o') - date_format($date1, 'o');
+ for ($i = 1; $i <= $year_diff; $i++) {
+ date_modify($date1, '+1 year');
+ $week_diff += date_iso_weeks_in_year($date1);
+ }
+ return $week_diff;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Start and end dates for a calendar week, adjusted to use the
+ * chosen first day of week for this site.
+ */
+function date_week_range($week, $year) {
+ if (variable_get('date_api_use_iso8601', FALSE)) {
+ return date_iso_week_range($week, $year);
+ }
+
+ $min_date = date_make_date($year .'-01-01 00:00:00', date_default_timezone_name());
+ date_timezone_set($min_date, date_default_timezone());
+
+ // move to the right week
+ date_modify($min_date, '+' . strval(7 * ($week - 1)) . ' days');
+
+ // move backwards to the first day of the week
+ $first_day = variable_get('date_first_day', 1);
+ $day_wday = date_format($min_date, 'w');
+ date_modify($min_date, '-' . strval((7 + $day_wday - $first_day) % 7) . ' days');
+
+ // move forwards to the last day of the week
+ $max_date = drupal_clone($min_date);
+ date_modify($max_date, '+7 days');
+
+ if (date_format($min_date, 'Y') != $year) {
+ $min_date = date_make_date($year .'-01-01 00:00:00', date_default_timezone());
+ }
+ return array($min_date, $max_date);
+}
+
+/**
+ * Start and end dates for an ISO week.
+ */
+function date_iso_week_range($week, $year) {
+
+ // Get to the last ISO week of the previous year.
+ $min_date = date_make_date(($year - 1) .'-12-28 00:00:00', date_default_timezone_name());
+ date_timezone_set($min_date, date_default_timezone());
+
+ // Find the first day of the first ISO week in the year.
+ date_modify($min_date, '+1 Monday');
+
+ // Jump ahead to the desired week for the beginning of the week range.
+ if ($week > 1) {
+ date_modify($min_date, '+ '. ($week - 1) .' weeks');
+ }
+
+ // move forwards to the last day of the week
+ $max_date = drupal_clone($min_date);
+ date_modify($max_date, '+7 days');
+ return array($min_date, $max_date);
+}
+
+/**
+ * The number of calendar weeks in a year.
+ *
+ * PHP week functions return the ISO week, not the calendar week.
+ *
+ * @param int $year
+ * @return int number of calendar weeks in selected year.
+ */
+function date_weeks_in_year($year) {
+ $date = date_make_date(($year + 1) . '-01-01 12:00:00', 'UTC');
+ date_modify($date, '-1 day');
+ return date_week(date_format($date, 'Y-m-d'));
+}
+
+/**
+ * The calendar week number for a date.
+ *
+ * PHP week functions return the ISO week, not the calendar week.
+ *
+ * @param string $date, in the format Y-m-d
+ * @return int calendar week number.
+ */
+function date_week($date) {
+ $date = drupal_substr($date, 0, 10);
+ $parts = explode('-', $date);
+ $date = date_make_date($date . ' 12:00:00', 'UTC');
+
+ // If we are using ISO weeks, this is easy.
+ if (variable_get('date_api_use_iso8601', FALSE)) {
+ return intval(date_format($date, 'W'));
+ }
+
+ $year_date = date_make_date($parts[0] . '-01-01 12:00:00', 'UTC');
+ $week = intval(date_format($date, 'W'));
+ $year_week = intval(date_format($year_date, 'W'));
+ $date_year = intval(date_format($date, 'o'));
+
+ // remove the leap week if it's present
+ if ($date_year > intval($parts[0])) {
+ $last_date = drupal_clone($date);
+ date_modify($last_date, '-7 days');
+ $week = date_format($last_date, 'W') + 1;
+ }
+ elseif ($date_year < intval($parts[0])) {
+ $week = 0;
+ }
+
+ if ($year_week != 1) $week++;
+
+ // convert to ISO-8601 day number, to match weeks calculated above
+ $iso_first_day = 1 + (variable_get('date_first_day', 1) + 6) % 7;
+
+ // if it's before the starting day, it's the previous week
+ if (intval(date_format($date, 'N')) < $iso_first_day) $week--;
+
+ // if the year starts before, it's an extra week at the beginning
+ if (intval(date_format($year_date, 'N')) < $iso_first_day) $week++;
+
+ return $week;
+}
+
+/**
+ * Date conversion helper function.
+ *
+ * A variety of ways to convert dates from one type to another.
+ * No timezone conversion is done in this operation, except
+ * when handling timestamps because create_date() assumes
+ * timestamps hold the UTC value for the time.
+ *
+ * @param mixed $date
+ * the date to convert
+ * @param string $from_type
+ * the type of date to convert from
+ * @param string $to_type
+ * the type of date to convert to
+ * @param string $tz
+ * the timezone of the supplied value, only needed when using timestamps
+ * for dates not set to UTC.
+ */
+function date_convert($date, $from_type, $to_type, $tz = 'UTC') {
+ if (empty($date) && !$date === 0) return NULL;
+ if (empty($from_type) || empty($to_type) || $from_type == $to_type) return $date;
+ switch ($from_type) {
+ case DATE_ARRAY:
+ if (!is_array($date)) return NULL;
+ // Make sure all parts exist to avoid PHP notices.
+ foreach (array('month', 'day', 'hour', 'minute', 'second') as $part) {
+ if (!isset($date[$part])) {
+ $date[$part] = '';
+ }
+ }
+ if (isset($date['ampm'])) {
+ if ($date['ampm'] == 'pm' && $date['hour'] < 12) $date['hour'] += 12;
+ if ($date['ampm'] == 'am' && $date['hour'] == 12) $date['hour'] -= 12;
+ }
+ $datetime = date_pad(intval($date['year']), 4) .'-'. date_pad(intval($date['month'])) .
+ '-'. date_pad(intval($date['day'])) .' '. date_pad(intval($date['hour'])) .
+ ':'. date_pad(intval($date['minute'])) .':'. date_pad(intval($date['second']));
+ switch ($to_type) {
+ case DATE_ISO:
+ return str_replace(' ', 'T', $datetime);
+ case DATE_DATETIME:
+ return $datetime;
+ case DATE_ICAL:
+ $replace = array(' ' => 'T', '-' => '', ':' => '');
+ return strtr($datetime, $replace);
+ case DATE_OBJECT:
+ return date_create($datetime, timezone_open($tz));
+ case DATE_UNIX:
+ $obj = date_create($datetime, timezone_open($tz));
+ return date_format($obj, 'U');
+ }
+ break;
+ case DATE_OBJECT:
+ if (!is_object($date)) return NULL;
+ $obj = $date;
+ break;
+ case DATE_DATETIME:
+ case DATE_ISO:
+ if (!preg_match(DATE_REGEX_LOOSE, $date)) return NULL;
+ $date = date_fuzzy_datetime($date);
+ $obj = date_create($date, timezone_open($tz));
+ break;
+ case DATE_ICAL:
+ if (!preg_match(DATE_REGEX_LOOSE, $date)) return NULL;
+ preg_match(DATE_REGEX_LOOSE, $date, $regs);
+ $datetime = date_pad($regs[1], 4) .'-'. date_pad($regs[2]) .'-'. date_pad($regs[3]) .
+ 'T'. date_pad($regs[5]) .':'. date_pad($regs[6]) .':'. date_pad($regs[7]);
+ $obj = date_create($datetime, timezone_open($tz));
+ break;
+ case DATE_UNIX:
+ if (!is_numeric($date)) return NULL;
+ // Special case when creating dates with timestamps.
+ // The date_create() function will assume date is UTC value
+ // and will ignore our timezone.
+ $obj = date_create("@$date", timezone_open('UTC'));
+ date_timezone_set($obj, timezone_open($tz));
+ break;
+ }
+ switch ($to_type) {
+ case DATE_OBJECT:
+ return $obj;
+ case DATE_DATETIME:
+ return date_format($obj, DATE_FORMAT_DATETIME);
+ case DATE_ISO:
+ return date_format($obj, DATE_FORMAT_ISO);
+ case DATE_ICAL:
+ return date_format($obj, DATE_FORMAT_ICAL);
+ case DATE_UNIX:
+ return date_format($obj, 'U');
+ case DATE_ARRAY:
+ $date_array = date_array($obj);
+ // ISO dates may contain zero values for some date parts,
+ // make sure they don't get lost in the conversion.
+ if ($from_type == DATE_ISO) {
+ $date_array = array_merge($date_array, date_iso_array($date));
+ }
+ return $date_array;
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * Create valid datetime value from incomplete ISO dates or arrays.
+ */
+function date_fuzzy_datetime($date) {
+ // A text ISO date, like MMMM-YY-DD HH:MM:SS
+ if (!is_array($date)) {
+ $date = date_iso_array($date);
+ }
+ // An date/time value in the format:
+ // array('date' => MMMM-YY-DD, 'time' => HH:MM:SS).
+ elseif (array_key_exists('date', $date) || array_key_exists('time', $date)) {
+ $date_part = array_key_exists('date', $date) ? $date['date'] : '';
+ $time_part = array_key_exists('time', $date) ? $date['time'] : '';
+ $date = date_iso_array(trim($date_part .' '. $time_part));
+ }
+ // Otherwise date must in in format:
+ // array('year' => YYYY, 'month' => MM, 'day' => DD).
+ if (empty($date['year'])) {
+ $date['year'] = date('Y');
+ }
+ if (empty($date['month'])) {
+ $date['month'] = 1;
+ }
+ if (empty($date['day'])) {
+ $date['day'] = 1;
+ }
+ foreach (array('hour', 'minute', 'second') as $part) {
+ if (empty($date[$part])) {
+ $date[$part] = 0;
+ }
+ }
+ $value = date_pad($date['year'], 4) .'-'. date_pad($date['month']) .'-'.
+ date_pad($date['day']) .' '. date_pad($date['hour']) .':'.
+ date_pad($date['minute']) .':'. date_pad($date['second']);
+ return $value;
+}
+
+/**
+ * Create an array of date parts from an ISO date.
+ */
+function date_iso_array($date) {
+ preg_match(DATE_REGEX_LOOSE, $date, $regs);
+ return array(
+ 'year' => isset($regs[1]) ? intval($regs[1]) : '',
+ 'month' => isset($regs[2]) ? intval($regs[2]) : '',
+ 'day' => isset($regs[3]) ? intval($regs[3]) : '',
+ 'hour' => isset($regs[5]) ? intval($regs[5]) : '',
+ 'minute' => isset($regs[6]) ? intval($regs[6]) : '',
+ 'second' => isset($regs[7]) ? intval($regs[7]) : '',
+ );
+}
+
+/**
+ * Create an array of values from a date object. Structured like the
+ * results of getdate() but not limited to the 32-bit signed range.
+ *
+ * @param object $obj
+ * @return array
+ */
+function date_array($obj) {
+ $year = intval(date_format($obj, 'Y'));
+ $dow = date_format($obj, 'w');
+ $days = date_week_days();
+ return array(
+ 'second' => (integer) date_format($obj, 's'),
+ 'minute' => (integer) date_format($obj, 'i'),
+ 'hour' => date_format($obj, 'G'),
+ 'day' => date_format($obj, 'j'),
+ 'wday' => $dow,
+ 'month' => date_format($obj, 'n'),
+ 'year' => date_format($obj, 'Y'),
+ 'yday' => date_format($obj, 'z'),
+ 'weekday' => $days[$dow],
+ 'month_name' => date_format($obj, 'F'),
+ 0 => date_format($obj, 'U'));
+}
+
+/**
+ * Extract integer value of any date part from any type of date.
+ *
+ * Example:
+ * date_part_extract('2007-03-15 00:00', 'month', DATE_DATETIME)
+ * returns: 3
+ *
+ * @param mixed $date
+ * the date value to analyze.
+ * @param string $part
+ * the part of the date to extract, 'year', 'month', 'day', 'hour', 'minute', 'second'
+ * @param string $type
+ * the type of date supplied, DATE_ISO, DATE_UNIX, DATE_DATETIME, or DATE_OBJECT;
+ * @return integer
+ * the integer value of the requested date part.
+ */
+function date_part_extract($date, $part, $type = DATE_DATETIME, $tz = 'UTC') {
+ $formats = array('year' => 'Y', 'month' => 'n', 'day' => 'j',
+ 'hour' => 'G', 'minute' => 'i', 'second' => 's');
+ $positions = array('year' => 0, 'month' => 5, 'day' => 8,
+ 'hour' => 11, 'minute' => 14, 'second' => 17);
+ $ipositions = array('year' => 0, 'month' => 4, 'day' => 6,
+ 'hour' => 9, 'minute' => 11, 'second' => 13);
+ switch ($type) {
+ case DATE_ARRAY:
+ return (integer) array_key_exists($part, $date) ? $date[$part] : NULL;
+ case DATE_DATETIME:
+ case DATE_ISO:
+ return (integer) drupal_substr($date, $positions[$part], $part == 'year' ? 4 : 2);
+ case DATE_ICAL:
+ return (integer) drupal_substr($date, $ipositions[$part], $part == 'year' ? 4 : 2);
+ case DATE_UNIX:
+ // Special case when creating dates with timestamps.
+ // The date_create() function will assume date is UTC value
+ // and will ignore our timezone.
+ $date = date_create("@$date", timezone_open('UTC'));
+ date_timezone_set($date, timezone_open($tz));
+ return date_format($date, $formats[$part]);
+ case DATE_OBJECT:
+ return date_format($date, $formats[$part]);
+ }
+}
+
+/**
+ * Functions to test the validity of a date in various formats.
+ * Has special case for ISO dates and arrays which can be missing
+ * month and day and still be valid.
+ *
+ * @param $type
+ * could be DATE_ARRAY, DATE_UNIX, DATE_DATETIME, DATE_ISO, or DATE_OBJECT
+ * @param $granularity
+ * The granularity of the date value provided. Set this for partial
+ * dates so they pass validation.
+ */
+function date_is_valid($date, $type = DATE_DATETIME, $granularity = array('year', 'month', 'day', 'hour', 'minute')) {
+
+ // Check that the value is properly structured.
+ // Remember that DATE_UNIX can have a valid value of '0', which is 'empty'.
+ if (empty($date) && $type != DATE_UNIX) return FALSE;
+ if ($type == DATE_OBJECT && !is_object($date)) return FALSE;
+ if (($type == DATE_ISO || $type == DATE_DATETIME) && (!is_string($date) || !preg_match(DATE_REGEX_LOOSE, $date))) return FALSE;
+ if ($type == DATE_UNIX and !is_numeric($date)) return FALSE;
+ if ($type == DATE_ARRAY and !is_array($date)) return FALSE;
+
+ // Make sure integer values are sent to checkdate.
+ $year = intval(date_part_extract($date, 'year', $type));
+ $month = intval(date_part_extract($date, 'month', $type));
+ $day = intval(date_part_extract($date, 'day', $type));
+ if (checkdate($month, $day, $year)) {
+ return TRUE;
+ }
+
+ // If this is an incomplete date (year only or year and month only),
+ // need special handling, partial dates can have empty date parts.
+ $max_granularity = $granularity;
+ $max_granularity = array_pop($max_granularity);
+ if (!in_array($max_granularity, array('year', 'month'))) {
+ if (in_array('year', $granularity) && !date_valid_year($year)) {
+ return FALSE;
+ }
+ elseif (in_array('month', $granularity) && !date_valid_month($month)) {
+ return FALSE;
+ }
+ elseif (in_array('day', $granularity) && !date_valid_day($day, $month, $year)) {
+ return FALSE;
+ }
+ }
+ // ISO dates and arrays can have empty date parts.
+ elseif ($type == DATE_ISO || $type == DATE_ARRAY) {
+ if (!date_valid_year($year)) {
+ return FALSE;
+ }
+ elseif (!empty($month) && !date_valid_month($month)) {
+ return FALSE;
+ }
+ elseif (!empty($day) && !date_valid_day($day, $month, $year)) {
+ return FALSE;
+ }
+ }
+ elseif (!date_valid_year($year) || !date_valid_month($month) || !date_valid_day($day, $month, $year)) {
+ // Unix and datetime are expected to have at least a year, month, and day.
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+function date_valid_year($year) {
+ if (variable_get('date_max_year', 4000) < $year || variable_get('date_min_year', 1) > $year) {
+ return FALSE;
+ }
+ else {
+ return TRUE;
+ }
+}
+
+function date_valid_month($month) {
+ if (12 < $month || 0 > $month) {
+ return FALSE;
+ }
+ else {
+ return TRUE;
+ }
+}
+
+function date_valid_day($day, $month = NULL, $year = NULL) {
+ $days_in_month = !empty($month) && !empty($year) ? date_days_in_month($year, $month) : 31;
+ if ($days_in_month < $day || 1 > $day) {
+ return FALSE;
+ }
+ else {
+ return TRUE;
+ }
+}
+
+/**
+ * Helper function to left pad date parts with zeros.
+ * Provided because this is needed so often with dates.
+ *
+ * @param int $value
+ * the value to pad
+ * @param int $size
+ * total size expected, usually 2 or 4
+ * @return string the padded value
+ */
+function date_pad($value, $size = 2) {
+ return sprintf("%0". $size ."d", $value);
+}
+
+/**
+ * Function to figure out if any time data is to be collected or displayed.
+ *
+ * @param granularity
+ * an array like ('year', 'month', 'day', 'hour', 'minute', 'second');
+ */
+function date_has_time($granularity) {
+ if (!is_array($granularity)) $granularity = array();
+ return sizeof(array_intersect($granularity, array('hour', 'minute', 'second'))) > 0 ? TRUE : FALSE;
+}
+
+function date_has_date($granularity) {
+ if (!is_array($granularity)) $granularity = array();
+ return sizeof(array_intersect($granularity, array('year', 'month', 'day'))) > 0 ? TRUE : FALSE;
+}
+/**
+ * Recalculate a date so it only includes elements from a granularity
+ * array. Helps prevent errors when unwanted values round up and ensures
+ * that unwanted date part values don't get stored in the database.
+ *
+ * Example:
+ * date_limit_value('2007-05-15 04:45:59', array('year', 'month', 'day'))
+ * returns '2007-05-15 00:00:00'
+ *
+ * @param $date
+ * a date value
+ * @param $granularity
+ * an array of allowed date parts, like ('year', 'month', 'day', 'hour', 'minute', 'second');
+ * @param $type
+ * the type of date value provided,
+ * DATE_DATETIME, DATE_ISO, DATE_UNIX, or DATE_ARRAY
+ * @return
+ * the date with the unwanted parts reset to zeros (or ones if zeros are
+ * invalid for that date type).
+ */
+function date_limit_value($date, $granularity, $type = DATE_DATETIME) {
+ if (!date_is_valid($date, $type, $granularity) || !$nongranularity = date_nongranularity($granularity)) {
+ return $date;
+ }
+ else {
+ $date = date_convert($date, $type, DATE_ARRAY);
+ foreach ($nongranularity as $level) {
+ switch ($level) {
+ case 'second':
+ $date['second'] = 0;
+ break;
+ case 'minute':
+ $date['minute'] = 0;
+ break;
+ case 'hour':
+ $date['hour'] = 0;
+ break;
+ case 'month':
+ $date['month'] = $type != DATE_ISO ? 1 : 0;
+ break;
+ case 'day':
+ $date['day'] = $type != DATE_ISO ? 1 : 0;
+ break;
+ }
+ }
+ return date_convert($date, DATE_ARRAY, $type);
+ }
+}
+
+/**
+ * Rewrite a format string so it only includes elements from a
+ * specified granularity array.
+ *
+ * Example:
+ * date_limit_format('F j, Y - H:i', array('year', 'month', 'day'));
+ * returns 'F j, Y'
+ *
+ * @param $format
+ * a format string
+ * @param $granularity
+ * an array of allowed date parts, all others will be removed
+ * array('year', 'month', 'day', 'hour', 'minute', 'second');
+ * @return
+ * a format string with all other elements removed
+ */
+function date_limit_format($format, $granularity) {
+ // If punctuation has been escaped, remove the escaping.
+ // Done using strtr because it is easier than getting the
+ // escape character extracted using preg_replace.
+ $replace = array(
+ '\-' => '-',
+ '\:' => ':',
+ "\'" => "'",
+ '\.' => '.',
+ '\,' => ',',
+ );
+ $format = strtr($format, $replace);
+
+ // Get the 'T' out of ISO date formats that don't have
+ // both date and time.
+ if (!date_has_time($granularity) || !date_has_date($granularity)) {
+ $format = str_replace('\T', ' ', $format);
+ $format = str_replace('T', ' ', $format);
+ }
+
+ $regex = array();
+ if (!date_has_time($granularity)) {
+ $regex[] = '((? 'month',
+ * 1 => 'day',
+ * 2 => 'year',
+ * 3 => 'hour',
+ * 4 => 'minute',
+ * );
+ *
+ * @param string $format
+ * @return array of ordered granularity elements in this format string
+ */
+function date_format_order($format) {
+ $order = array();
+ if (empty($format)) return $order;
+ $max = drupal_strlen($format);
+ for ($i = 0; $i <= $max; $i++) {
+ if (!isset($format[$i])) break;
+ $c = $format[$i];
+ switch ($c) {
+ case 'd':
+ case 'j':
+ $order[] = 'day';
+ break;
+ case 'F':
+ case 'M':
+ case 'm':
+ case 'n':
+ $order[] = 'month';
+ break;
+ case 'Y':
+ case 'y':
+ $order[] = 'year';
+ break;
+ case 'g':
+ case 'G':
+ case 'h':
+ case 'H':
+ $order[] = 'hour';
+ break;
+ case 'i':
+ $order[] = 'minute';
+ break;
+ case 's':
+ $order[] = 'second';
+ break;
+ }
+ }
+ return $order;
+}
+
+/**
+ * An difference array of granularity elements that are NOT in the
+ * granularity array. Used by functions that strip unwanted
+ * granularity elements out of formats and values.
+ *
+ * @param $granularity
+ * an array like ('year', 'month', 'day', 'hour', 'minute', 'second');
+ */
+function date_nongranularity($granularity) {
+ return array_diff(array('year', 'month', 'day', 'hour', 'minute', 'second', 'timezone'), (array) $granularity);
+}
+
+/**
+ * Implementation of hook_simpletest().
+ */
+function date_api_simpletest() {
+ $dir = drupal_get_path('module', 'date_api') .'/tests';
+ $tests = file_scan_directory($dir, '\.test$');
+ return array_keys($tests);
+}
+
+/**
+ * Implementation of hook_elements().
+ */
+function date_api_elements() {
+ require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_elements.inc');
+ return _date_api_elements();
+}
+
+function date_api_theme() {
+ $path = drupal_get_path('module', 'date_api');
+ $base = array(
+ 'file' => 'theme.inc',
+ 'path' => "$path/theme",
+ );
+ return array(
+ 'date_nav_title' => $base + array('arguments' => array('type' => NULL, 'view' => NULL)),
+ 'date_vcalendar' => $base + array('arguments' => array('events' => NULL, 'calname' => NULL)),
+ 'date_vevent' => $base + array('arguments' => array('event' => NULL)),
+ 'date_valarm' => $base + array('arguments' => array('alarm' => NULL)),
+ 'date_timezone' => $base + array('arguments' => array('element' => NULL)),
+ 'date_select' => $base + array('arguments' => array('element' => NULL)),
+ 'date_text' => $base + array('arguments' => array('element' => NULL)),
+ 'date_select_element' => $base + array('arguments' => array('element' => NULL)),
+ 'date_textfield_element' => $base + array('arguments' => array('element' => NULL)),
+ 'date_date_part_hour_prefix' => $base + array('arguments' => array('element' => NULL)),
+ 'date_part_minsec_prefix' => $base + array('arguments' => array('element' => NULL)),
+ 'date_part_label_year' => $base + array('arguments' => array('element' => NULL)),
+ 'date_part_label_month' => $base + array('arguments' => array('element' => NULL)),
+ 'date_part_label_day' => $base + array('arguments' => array('element' => NULL)),
+ 'date_part_label_hour' => $base + array('arguments' => array('element' => NULL)),
+ 'date_part_label_minute' => $base + array('arguments' => array('element' => NULL)),
+ 'date_part_label_second' => $base + array('arguments' => array('element' => NULL)),
+ 'date_part_label_ampm' => $base + array('arguments' => array('element' => NULL)),
+ 'date_part_label_timezone' => $base + array('arguments' => array('element' => NULL)),
+ 'date_views_filter_form' => $base + array(
+ 'template' => 'date-views-filter-form',
+ 'arguments' => array('form' => NULL)),
+ 'date_calendar_day' => $base + array('arguments' => array('date' => NULL)),
+ 'date_time_ago' => $base + array('arguments' => array('start_date' => NULL, 'end_date' => NULL, 'interval' => NULL)));
+}
+
+/**
+ * Wrapper around date handler setting for timezone.
+ */
+function date_api_set_db_timezone($offset = '+00:00') {
+ require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_sql.inc');
+ $handler = new date_sql_handler();
+ return $handler->set_db_timezone($offset);
+}
+
+/**
+ * Function to figure out which local timezone applies to a date and select it
+ */
+function date_get_timezone($handling, $timezone = '') {
+ switch ($handling) {
+ case ('date'):
+ $timezone = !empty($timezone) ? $timezone : date_default_timezone_name();
+ break;
+ case ('utc'):
+ $timezone = 'UTC';
+ break;
+ default:
+ $timezone = date_default_timezone_name();
+ }
+ return $timezone > '' ? $timezone : date_default_timezone_name();
+}
+
+/**
+ * Function to figure out which db timezone applies to a date and select it
+ */
+function date_get_timezone_db($handling, $timezone = '') {
+ switch ($handling) {
+ case ('none'):
+ $timezone = date_default_timezone_name();
+ break;
+ default:
+ $timezone = 'UTC';
+ break;
+ }
+ return $timezone > '' ? $timezone : 'UTC';
+}
+
+/**
+ * Wrapper function to make sure this function will always work.
+ */
+function date_api_views_fetch_fields($base, $type) {
+ if (!module_exists('views')) {
+ return array();
+ }
+ require_once('./'. drupal_get_path('module', 'views') .'/includes/admin.inc');
+ return views_fetch_fields($base, $type);
+}
+
+/**
+ * Get the list of date formats for a particular format length.
+ *
+ * @param $type
+ * The format type: 'short', 'medium', 'long', 'custom'. If empty, then all
+ * available formats will be returned.
+ * @param $reset
+ * Whether or not to reset this function's internal cache (defaults to FALSE).
+ * @return
+ * Array of date formats.
+ */
+function date_get_formats($type = NULL, $reset = FALSE) {
+ static $_date_formats;
+
+ if ($reset || !isset($_date_formats)) {
+ $_date_formats = _date_formats_build();
+ }
+
+ return $type ? (isset($_date_formats[$type]) ? $_date_formats[$type] : FALSE) : $_date_formats;
+}
+
+/**
+ * Get the format details for a particular id.
+ *
+ * @param $dfid
+ * Identifier of a date format string.
+ * @return
+ * Array of date format details.
+ */
+function date_get_format($dfid) {
+ $result = db_query('SELECT df.dfid, df.format, df.type, df.locked FROM {date_formats} df WHERE df.dfid = %d', $dfid);
+ return db_fetch_array($result);
+}
+
+/**
+ * Get the list of available date format types and attributes.
+ *
+ * @param $type
+ * The format type, e.g. 'short', 'medium', 'long', 'custom'. If empty, then
+ * all attributes for that type will be returned.
+ * @param $reset
+ * Whether or not to reset this function's internal cache (defaults to FALSE).
+ * @return
+ * Array of date format types.
+ */
+function date_get_format_types($type = NULL, $reset = FALSE) {
+ static $_date_format_types;
+
+ if ($reset || !isset($_date_format_types)) {
+ $_date_format_types = _date_format_types_build();
+ }
+
+ return $type ? (isset($_date_format_types[$type]) ? $_date_format_types[$type] : FALSE) : $_date_format_types;
+}
+
+/**
+ * Implementation of hook_flush_caches().
+ */
+function date_api_flush_caches() {
+ // Rebuild list of date formats.
+ date_formats_rebuild();
+ return array();
+}
+
+/**
+ * Resets the database cache of date formats, and saves all new date formats to
+ * the database.
+ */
+function date_formats_rebuild() {
+ $date_formats = date_get_formats(NULL, TRUE);
+
+ foreach ($date_formats as $format_type => $formats) {
+ foreach ($formats as $format => $info) {
+ date_format_save($info);
+ }
+ }
+
+ // Rebuild configured date formats locale list.
+ date_format_locale(NULL, NULL, TRUE);
+
+ _date_formats_build();
+}
+
+/**
+ * Save a date format type to the database.
+ *
+ * @param $date_format_type
+ * An array of attributes for a date format type.
+ */
+function date_format_type_save($date_format_type) {
+ $type = array();
+ $type['type'] = $date_format_type['type'];
+ $type['title'] = $date_format_type['title'];
+ $type['locked'] = $date_format_type['locked'];
+
+ // Update date_format table.
+ if (isset($date_format_type['is_new']) && !empty($date_format_type['is_new'])) {
+ drupal_write_record('date_format_types', $type);
+ }
+ else {
+ drupal_write_record('date_format_types', $type, 'type');
+ }
+}
+
+/**
+ * Delete a date format type from the database.
+ *
+ * @param $date_format_type
+ * The date format type name.
+ */
+function date_format_type_delete($date_format_type) {
+ db_query("DELETE FROM {date_formats} WHERE type = '%s'", $date_format_type);
+ db_query("DELETE FROM {date_format_types} WHERE type = '%s'", $date_format_type);
+ db_query("DELETE FROM {date_format_locale} WHERE type = '%s'", $date_format_type);
+}
+
+/**
+ * Save a date format to the database.
+ *
+ * @param $date_format
+ * An array of attributes for a date format.
+ */
+function date_format_save($date_format) {
+ $format = array();
+ $format['type'] = $date_format['type'];
+ $format['format'] = $date_format['format'];
+ $format['locked'] = $date_format['locked'];
+
+ // Update date_format table.
+ if (isset($date_format['is_new']) && !empty($date_format['is_new'])) {
+ drupal_write_record('date_formats', $format);
+ }
+ else {
+ drupal_write_record('date_formats', $format, array('format', 'type'));
+ }
+
+ $languages = language_list('enabled');
+ $languages = $languages[1];
+ // If site_country module is enabled, add country specific languages to
+ // languages array.
+ if (module_exists('site_country')) {
+ $country_code = variable_get('site_country_default_country', '');
+ if (!empty($country_code)) {
+ foreach ($languages as $langcode => $details) {
+ $country_language = $langcode . '-' . $country_code;
+ if (drupal_strlen($langcode) == 2 && !in_array($country_language, array_keys($languages))) {
+ $name = $details->name;
+ $languages[$country_language] = "$name ($country_code)";
+ }
+ }
+ }
+ }
+
+ $locale_format = array();
+ $locale_format['type'] = $date_format['type'];
+ $locale_format['format'] = $date_format['format'];
+
+ // Check if the suggested language codes are configured and enabled.
+ if (!empty($date_format['locales'])) {
+ foreach ($date_format['locales'] as $langcode) {
+ // Only proceed if language is enabled.
+ if (in_array($langcode, $languages)) {
+ $is_existing = db_result(db_query("SELECT COUNT(*) FROM {date_format_locale} WHERE type = '%s' AND language = '%s'", $date_format['type'], $langcode));
+ if (!$is_existing) {
+ $locale_format['language'] = $langcode;
+ drupal_write_record('date_format_locale', $locale_format);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Delete a date format from the database.
+ *
+ * @param $date_format_id
+ * The date format string identifier.
+ */
+function date_format_delete($date_format_id) {
+ db_query("DELETE FROM {date_formats} WHERE dfid = '%d'", $date_format_id);
+}
+
+/**
+ * Builds and returns the list of available date format types.
+ *
+ * @return
+ * Array of date format types.
+ */
+function _date_format_types_build() {
+ $types = array();
+
+ // Prevent errors in the upgrade before the date_format_types table exists.
+ if (defined('MAINTENANCE_MODE') && !db_table_exists('date_format_types')) {
+ return $types;
+ }
+
+ // Get list of modules which implement hook_date_format_types().
+ $modules = module_implements('date_format_types');
+
+ foreach ($modules as $module) {
+ $module_types = module_invoke($module, 'date_format_types');
+ foreach ($module_types as $module_type => $type_title) {
+ $type = array();
+ $type['module'] = $module;
+ $type['type'] = $module_type;
+ $type['title'] = $type_title;
+ $type['locked'] = 1;
+ $type['is_new'] = TRUE; // Will be over-ridden later if in the db.
+ $types[$module_type] = $type;
+ }
+ }
+
+ // Get custom formats added to the database by the end user.
+ $result = db_query('SELECT dft.type, dft.title, dft.locked FROM {date_format_types} dft ORDER BY dft.title');
+ while ($object = db_fetch_object($result)) {
+ if (!in_array($object->type, $types)) {
+ $type = array();
+ $type['is_new'] = FALSE;
+ $type['module'] = '';
+ $type['type'] = $object->type;
+ $type['title'] = $object->title;
+ $type['locked'] = $object->locked;
+ $types[$object->type] = $type;
+ }
+ else {
+ $type = array();
+ $type['is_new'] = FALSE; // Over-riding previous setting.
+ $types[$object->type] = array_merge($types[$object->type], $type);
+ }
+ }
+
+ // Allow other modules to modify these format types.
+ drupal_alter('date_format_types', $types);
+
+ return $types;
+}
+
+/**
+ * Builds and returns the list of available date formats.
+ *
+ * @return
+ * Array of date formats.
+ */
+function _date_formats_build() {
+ $date_formats = array();
+
+ // Prevent errors in the upgrade before the date_format table exists.
+ if (defined('MAINTENANCE_MODE') && !db_table_exists('date_format')) {
+ return $date_formats;
+ }
+
+ // First handle hook_date_format_types().
+ $types = _date_format_types_build();
+ foreach ($types as $type => $info) {
+ date_format_type_save($info);
+ }
+
+ // Get formats supplied by various contrib modules.
+ $module_formats = module_invoke_all('date_formats');
+
+ foreach ($module_formats as $module_format) {
+ $module_format['locked'] = 1; // System types are locked.
+ // If no format type is specified, assign 'custom'.
+ if (!isset($module_format['type'])) {
+ $module_format['type'] = 'custom';
+ }
+ if (!in_array($module_format['type'], array_keys($types))) {
+ continue;
+ }
+ if (!isset($date_formats[$module_format['type']])) {
+ $date_formats[$module_format['type']] = array();
+ }
+
+ // If another module already set this format, merge in the new settings.
+ if (isset($date_formats[$module_format['type']][$module_format['format']])) {
+ $date_formats[$module_format['type']][$module_format['format']] = array_merge_recursive($date_formats[$module_format['type']][$module_format['format']], $format);
+ }
+ else {
+ // This setting will be overridden later if it already exists in the db.
+ $module_format['is_new'] = TRUE;
+ $date_formats[$module_format['type']][$module_format['format']] = $module_format;
+ }
+ }
+
+ // Get custom formats added to the database by the end user.
+ $result = db_query('SELECT df.dfid, df.format, df.type, df.locked, dfl.language FROM {date_formats} df LEFT JOIN {date_format_types} dft ON df.type = dft.type LEFT JOIN {date_format_locale} dfl ON df.format = dfl.format AND df.type = dfl.type ORDER BY df.type, df.format');
+ while ($object = db_fetch_object($result)) {
+ // If this format type isn't set, initialise the array.
+ if (!isset($date_formats[$object->type])) {
+ $date_formats[$object->type] = array();
+ }
+ // If this format not already present, add it to the array.
+ if (!isset($date_formats[$object->type][$object->format])) {
+ // We don't set 'is_new' as it is already in the db.
+ $format = array();
+ $format['module'] = '';
+ $format['dfid'] = $object->dfid;
+ $format['format'] = $object->format;
+ $format['type'] = $object->type;
+ $format['locked'] = $object->locked;
+ $format['locales'] = array($object->language);
+ $date_formats[$object->type][$object->format] = $format;
+ }
+ // Format already present, so merge in settings.
+ else {
+ $format = array();
+ $format['is_new'] = FALSE; // It's in the db, so override this setting.
+ $format['dfid'] = $object->dfid;
+ $format['format'] = $object->format;
+ $format['type'] = $object->type;
+ $format['locked'] = $object->locked;
+ if (!empty($object->language)) {
+ $format['locales'] = array_merge($date_formats[$object->type][$object->format]['locales'], array($object->language));
+ }
+ $date_formats[$object->type][$object->format] = array_merge($date_formats[$object->type][$object->format], $format);
+ }
+ }
+
+ // Allow other modules to modify these formats.
+ drupal_alter('date_formats', $date_formats);
+
+ return $date_formats;
+}
+
+/**
+ * Get the appropriate date format for a type and locale.
+ *
+ * @param $langcode
+ * Language code for the current locale. This can be a 2 character language
+ * code like 'en', 'fr', or a longer 5 character code like 'en-gb'.
+ * @param $type
+ * Date format type: short, medium, long, custom.
+ * @param $reset
+ * Whether or not to reset this function's internal cache (defaults to FALSE).
+ * @return
+ * The format string, or NULL if no matching format found.
+ */
+function date_format_locale($langcode = NULL, $type = NULL, $reset = FALSE) {
+ static $formats;
+
+ if ($reset || empty($formats)) {
+ $formats = array();
+ $result = db_query("SELECT format, type, language FROM {date_format_locale}");
+ while ($object = db_fetch_object($result)) {
+ if (!isset($formats[$object->language])) {
+ $formats[$object->language] = array();
+ }
+ $formats[$object->language][$object->type] = $object->format;
+ }
+ }
+
+ if ($type && $langcode && !empty($formats[$langcode][$type])) {
+ return $formats[$langcode][$type];
+ }
+ elseif ($langcode && !empty($formats[$langcode])) {
+ return $formats[$langcode];
+ }
+
+ return FALSE;
+}
+
+/**
+ * Helper function for BYDAY options in Date Repeat
+ * and for converting back and forth from '+1' to 'First'.
+ */
+function date_order_translated() {
+ return array(
+ '+1' => date_t('First', 'date_order'),
+ '+2' => date_t('Second', 'date_order'),
+ '+3' => date_t('Third', 'date_order'),
+ '+4' => date_t('Fourth', 'date_order'),
+ '+5' => date_t('Fifth', 'date_order'),
+ '-1' => date_t('Last', 'date_order_reverse'),
+ '-2' => date_t('Next to last', 'date_order_reverse'),
+ '-3' => date_t('Third from last', 'date_order_reverse'),
+ '-4' => date_t('Fourth from last', 'date_order_reverse'),
+ '-5' => date_t('Fifth from last', 'date_order_reverse')
+ );
+}
+
+function date_order() {
+ return array(
+ '+1' => 'First',
+ '+2' => 'Second',
+ '+3' => 'Third',
+ '+4' => 'Fourth',
+ '+5' => 'Fifth',
+ '-1' => 'Last',
+ '-2' => '-2',
+ '-3' => '-3',
+ '-4' => '-4',
+ '-5' => '-5'
+ );
+}
+
+/**
+ * Implementation of hook_views_api().
+ *
+ * This one is used as the base to reduce errors when updating.
+ */
+function date_api_views_api() {
+ return array(
+ 'api' => 2,
+ 'path' => drupal_get_path('module', 'date_api') .'/includes',
+ );
+}
+
+/**
+ * Implementation of hook_date_api_fields().
+ * on behalf of core fields.
+ *
+ * All modules that create custom fields that use the
+ * 'views_handler_field_date' handler can provide
+ * additional information here about the type of
+ * date they create so the date can be used by
+ * the Date API views date argument and date filter.
+ */
+function date_api_date_api_fields($field) {
+ $values = array(
+ // The type of date: DATE_UNIX, DATE_ISO, DATE_DATETIME.
+ 'sql_type' => DATE_UNIX,
+ // Timezone handling options: 'none', 'site', 'date', 'utc'.
+ 'tz_handling' => 'site',
+ // Needed only for dates that use 'date' tz_handling.
+ 'timezone_field' => '',
+ // Needed only for dates that use 'date' tz_handling.
+ 'offset_field' => '',
+ // Array of "table.field" values for related fields that should be
+ // loaded automatically in the Views SQL.
+ 'related_fields' => array(),
+ // Granularity of this date field's db data.
+ 'granularity' => array('year', 'month', 'day', 'hour', 'minute', 'second'),
+ );
+
+ switch ($field) {
+ case 'users.created':
+ case 'users.access':
+ case 'users.login':
+ case 'node.created':
+ case 'node.changed':
+ case 'node_revisions.timestamp':
+ case 'files.timestamp':
+ case 'node_counter.timestamp':
+ case 'accesslog.timestamp':
+ case 'comments.timestamp':
+ case 'node_comment_statistics.last_comment_timestamp':
+ return $values;
+ }
+}
+
+/**
+ * Rebuild the theme registry and all the caches.
+ * needed to pick up changes created by updated Views API
+ * and other changes to Views definitions.
+ */
+function date_api_views_clear() {
+ if (db_table_exists('cache_content')) {
+ db_query('DELETE FROM {cache_content}');
+ }
+ if (db_table_exists('cache_views')) {
+ db_query('DELETE FROM {cache_views}');
+ }
+ if (db_table_exists('views_object_cache')) {
+ db_query('DELETE FROM {views_object_cache}');
+ }
+ db_query("DELETE FROM {cache} where cid LIKE 'theme_registry%'");
+}
+
+/**
+ * Embed a view using a PHP snippet.
+ *
+ * This function is meant to be called from PHP snippets, should one wish to
+ * embed a view in a node or something. It's meant to provide the simplest
+ * solution and doesn't really offer a lot of options, but breaking the function
+ * apart is pretty easy, and this provides a worthwhile guide to doing so.
+ *
+ * Note that this function does NOT display the title of the view. If you want
+ * to do that, you will need to do what this function does manually, by
+ * loading the view, getting the preview and then getting $view->get_title().
+ *
+ * @param $name
+ * The name of the view to embed.
+ *
+ * @param $display_id
+ * 'calendar_1' will display the calendar page,
+ * 'calendar_block_1' will display the calendar block.
+ *
+ * @param $settings
+ * an array of view settings to use to override view default values;
+ *
+ * Include a setting for 'block_identifier, the identifier to use
+ * for this embedded view. All embedded views that use the same
+ * identifier will move together, or provide different identifiers
+ * to keep them independent. The identifier will be used in the url
+ * as a querystring, like: node/27?mini=calendar/2008-10.
+ *
+ * @param ...
+ * Any additional parameters will be passed as arguments.
+ */
+function date_embed_view($name, $display_id = 'default', $settings = array(), $args = array()) {
+ $view = views_get_view($name);
+ if (!$view) {
+ return;
+ }
+ if (!empty($settings)) {
+ foreach ($settings as $key => $setting) {
+ $view->$key = $setting;
+ }
+ }
+ if (!isset($view->date_info->block_identifier)) {
+ $view->date_info->block_identifier = 'mini';
+ }
+ return $view->preview($display_id, $args);
+}
+
+/**
+ * Figure out the URL of the date view we're currently looking at,
+ * adapted to various date types or specific date arguments.
+ *
+ * @param $date_type
+ * - if not empty, return the url of a specific date type.
+ * @param $date_arg
+ * - if not empty, return the url for a view with a specific date argument.
+ * @param $force_view_url
+ * - always use the view url, even if embedded.
+ * @return
+ * return the requested view url.
+ */
+function date_real_url($view, $date_type = NULL, $date_arg = NULL, $force_view_url = FALSE) {
+ $args = $view->args;
+ $pos = $view->date_info->date_arg_pos;
+
+ // The View arguments array is indexed numerically but is not necessarily
+ // in numerical order. Sort the arguments to ensure the correct order.
+ ksort($args);
+
+ // If there are empty arguments before the date argument,
+ // pad them with the wildcard so the date argument will be in
+ // the right position.
+ if (count($args) < $pos) {
+ foreach ($view->argument as $name => $argument) {
+ if ($argument->position == $pos) {
+ break;
+ }
+ $args[] = $argument->options['wildcard'];
+ }
+ }
+
+ if (!empty($date_type)) {
+ switch ($date_type) {
+ case 'year':
+ $args[$pos] = date_pad($view->date_info->year, 4);
+ break;
+ case 'week':
+ $args[$pos] = date_pad($view->date_info->year, 4) .'-W'. date_pad($view->date_info->week);
+ break;
+ case 'day':
+ $args[$pos] = date_pad($view->date_info->year, 4) .'-'. date_pad($view->date_info->month) .'-'. date_pad($view->date_info->day);
+ break;
+ default:
+ $args[$pos] = date_pad($view->date_info->year, 4) .'-'. date_pad($view->date_info->month);
+ break;
+ }
+ }
+ elseif (!empty($date_arg)) {
+ $args[$pos] = $date_arg;
+ }
+ else {
+ $args = $view->args;
+ }
+ // Is this an embedded or a block view?
+ if (!$force_view_url &&
+ (!empty($view->preview) || !empty($view->date_info->block_identifier))) {
+ $url = $view->get_url($args);
+ $key = date_block_identifier($view);
+ if (!empty($key)) {
+ return url($_GET['q'], array(
+ 'query' => date_querystring($view, array($key => $url)),
+ 'absolute' => TRUE));
+ }
+ }
+ // Normal views may need querystrings appended to them
+ // if they use exposed filters.
+ return url($view->get_url($args), array(
+ 'query' => date_querystring($view),
+ 'absolute' => TRUE));
+}
+
+/**
+ * Pick up filter and sort info from url.
+ */
+function date_querystring($view, $extra_params = array()) {
+ $query_params = array_merge($_GET, $extra_params);
+ // Allow NULL params to be removed from the query string.
+ foreach ($extra_params AS $key => $value) {
+ if (!isset($value)) {
+ unset($query_params[$key]);
+ }
+ }
+ // Filter the special "q" and "view" variables out of the query string.
+ $exclude = array('q');
+ $query = drupal_query_string_encode($query_params, $exclude);
+ // To prevent an empty query string from adding a "?" on to the end of a URL,
+ // we return NULL.
+ return !empty($query) ? $query : NULL;
+}
+
+function date_block_identifier($view) {
+ if (!empty($view->block_identifier)) {
+ return $view->block_identifier;
+ }
+ return isset($view->date_info->block_identifier) ? $view->date_info->block_identifier : NULL;
+}
+
+/**
+ * Implementation of hook_form_alter().
+ *
+ * Add new submit handler for system_modules form.
+ */
+function date_api_form_system_modules_alter(&$form, $form_state, $form_id = 'system_modules') {
+ $form['#submit'][] = 'date_api_system_modules_submit';
+}
+
+/**
+ * Rebuild list of date formats when modules list is saved.
+ */
+function date_api_system_modules_submit($form, &$form_state) {
+ date_formats_rebuild();
+}
+
+/**
+ * Implementation of hook_form_alter().
+ *
+ * Remove the 'date_formats' section from the 'admin/settings/date-time' page.
+ * This form section is now part of the form at 'admin/settings/date-time/formats'.
+ * We add the formats as values to the form to avoid errors on submission
+ * of the form when expected values are missing in system_date_time_settings_submit().
+ *
+ * Add a form element to configure whether or not week numbers are ISO-8601 (default: FALSE == US/UK/AUS norm).
+ */
+function date_api_form_system_date_time_settings_alter(&$form, $form_state, $form_id = 'system_date_time_settings') {
+ include_once(drupal_get_path('module', 'date_api') .'/date_api.admin.inc');
+ $formats_form = date_api_date_formats_form($form_state);
+ $form['date_formats'] = $formats_form['date_formats'];
+ foreach ($form['date_formats'] as $key => $value) {
+ if (drupal_substr($key, 0, 1) != '#') {
+ $form['date_formats'][$key]['#type'] = 'value';
+ }
+ else {
+ unset($form['date_formats'][$key]);
+ }
+ }
+ $form['locale']['date_api_use_iso8601'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use ISO-8601 week numbers'),
+ '#default_value' => variable_get('date_api_use_iso8601', FALSE),
+ '#description' => t('IMPORTANT! If checked, First day of week MUST be set to Monday'),
+ );
+ $form['#validate'][] = 'date_api_form_system_settings_validate';
+}
+
+/**
+ * Validate that the option to use ISO weeks matches first day of week choice.
+ */
+function date_api_form_system_settings_validate(&$form, &$form_state) {
+ $form_values = $form_state['values'];
+ if ($form_values['date_api_use_iso8601'] && $form_values['date_first_day'] != 1) {
+ form_set_error('date_first_day', t('When using ISO-8601 week numbers, the first day of the week must be set to Monday.'));
+ }
+}
+
+/**
+ * Helper function; add system.js and javascript settings.
+ */
+function date_api_add_system_javascript() {
+ drupal_add_js(drupal_get_path('module', 'date_api') .'/date_api.js', 'module');
+ drupal_add_js(array('dateDateTime' => array('lookup' => url('admin/settings/date-time/formats/lookup'))), 'setting');
+}
+
+/**
+ * Return the date for a given format string via Ajax.
+ */
+function date_api_date_time_lookup() {
+ $result = date_format_date(date_now(), 'custom', $_GET['format']);
+ echo drupal_to_js($result);
+ exit;
+}
+
+/*
+ * Test validity of a date range string.
+ */
+function date_range_valid($string) {
+ $matches = preg_match('@^(\-[0-9]+|[0-9]{4}):([\+|\-][0-9]+|[0-9]{4})$@', $string);
+ return $matches < 1 ? FALSE : TRUE;
+}
+
+/**
+ * Split a string like -3:+3 or 2001:2010 into
+ * an array of min and max years.
+ *
+ * Center the range around the current year, if any, but expand it far
+ * enough so it will pick up the year value in the field in case
+ * the value in the field is outside the initial range.
+ */
+function date_range_years($string, $date = NULL) {
+ $this_year = date_format(date_now(), 'Y');
+ list($min_year, $max_year) = explode(':', $string);
+
+ // Valid patterns would be -5:+5, 0:+1, 2008:2010.
+ $plus_pattern = '@[\+|\-][0-9]{1,4}@';
+ $year_pattern = '@[0-9]{4}@';
+ if (!preg_match($year_pattern, $min_year, $matches)) {
+ if (preg_match($plus_pattern, $min_year, $matches)) {
+ $min_year = $this_year + $matches[0];
+ }
+ else {
+ $min_year = $this_year;
+ }
+ }
+ if (!preg_match($year_pattern, $max_year, $matches)) {
+ if (preg_match($plus_pattern, $max_year, $matches)) {
+ $max_year = $this_year + $matches[0];
+ }
+ else {
+ $max_year = $this_year;
+ }
+ }
+ // We expect the $min year to be less than the $max year.
+ // Some custom values for -99:+99 might not obey that.
+ if ($min_year > $max_year) {
+ $temp = $max_year;
+ $max_year = $min_year;
+ $min_year = $temp;
+ }
+ // If there is a current value, stretch the range to include it.
+ $value_year = is_object($date) ? date_format($date, 'Y') : '';
+ if (!empty($value_year)) {
+ $min_year = min($value_year, $min_year);
+ $max_year = max($value_year, $max_year);
+ }
+ return array($min_year, $max_year);
+}
+
+/**
+ * Convert a min and max year into a string like '-3:+1'.
+ *
+ * @param unknown_type $years
+ * @return unknown
+ */
+function date_range_string($years) {
+ $this_year = date_format(date_now(), 'Y');
+ if ($years[0] < $this_year) {
+ $min = '-'. ($this_year - $years[0]);
+ }
+ else {
+ $min = '+'. ($years[0] - $this_year);
+ }
+ if ($years[1] < $this_year) {
+ $max = '-'. ($this_year - $years[1]);
+ }
+ else {
+ $max = '+'. ($years[1] - $this_year);
+ }
+ return $min .':'. $max;
+}
+
+/**
+ * Implement hook_date_api_tables().
+ */
+function date_api_date_api_tables() {
+ return array('node', 'comments', 'users');
+}
+
+/**
+ * Determine if a from/to date combination qualify as 'All day'.
+ *
+ * @param object $date1, a string date in datetime format for the 'from' date.
+ * @param object $date2, a string date in datetime format for the 'to' date.
+ * @return TRUE or FALSE.
+ */
+function date_is_all_day($string1, $string2, $granularity = 'second', $increment = 1) {
+ if (empty($string1) || empty($string2)) {
+ return FALSE;
+ }
+ elseif (!in_array($granularity, array('hour', 'minute', 'second'))) {
+ return FALSE;
+ }
+
+ preg_match('/([0-9]{4}-[0-9]{2}-[0-9]{2}) (([0-9]{2}):([0-9]{2}):([0-9]{2}))/', $string1, $matches);
+ $count = count($matches);
+ $date1 = $count > 1 ? $matches[1] : '';
+ $time1 = $count > 2 ? $matches[2] : '';
+ $hour1 = $count > 3 ? intval($matches[3]) : 0;
+ $min1 = $count > 4 ? intval($matches[4]) : 0;
+ $sec1 = $count > 5 ? intval($matches[5]) : 0;
+ preg_match('/([0-9]{4}-[0-9]{2}-[0-9]{2}) (([0-9]{2}):([0-9]{2}):([0-9]{2}))/', $string2, $matches);
+ $count = count($matches);
+ $date2 = $count > 1 ? $matches[1] : '';
+ $time2 = $count > 2 ? $matches[2] : '';
+ $hour2 = $count > 3 ? intval($matches[3]) : 0;
+ $min2 = $count > 4 ? intval($matches[4]) : 0;
+ $sec2 = $count > 5 ? intval($matches[5]) : 0;
+ if (empty($date1) || empty($date2)) {
+ return FALSE;
+ }
+ if (empty($time1) || empty($time2)) {
+ return FALSE;
+ }
+
+ $tmp = date_seconds('s', TRUE, $increment);
+ $max_seconds = intval(array_pop($tmp));
+ $tmp = date_minutes('i', TRUE, $increment);
+ $max_minutes = intval(array_pop($tmp));
+
+ // See if minutes and seconds are the maximum allowed for an increment or the
+ // maximum possible (59), or 0.
+ switch ($granularity) {
+ case 'second':
+ $min_match = $time1 == '00:00:00'
+ || ($hour1 == 0 && $min1 == 0 && $sec1 == 0);
+ $max_match = $time2 == '00:00:00'
+ || ($hour2 == 23 && in_array($min2, array($max_minutes, 59)) && in_array($sec2, array($max_seconds, 59)))
+ || ($hour1 == 0 && $hour2 == 0 && $min1 == 0 && $min2 == 0 && $sec1 == 0 && $sec2 == 0);
+ break;
+ case 'minute':
+ $min_match = $time1 == '00:00:00'
+ || ($hour1 == 0 && $min1 == 0);
+ $max_match = $time2 == '00:00:00'
+ || ($hour2 == 23 && in_array($min2, array($max_minutes, 59)))
+ || ($hour1 == 0 && $hour2 == 0 && $min1 == 0 && $min2 == 0);
+ break;
+ case 'hour':
+ $min_match = $time1 == '00:00:00'
+ || ($hour1 == 0);
+ $max_match = $time2 == '00:00:00'
+ || ($hour2 == 23)
+ || ($hour1 == 0 && $hour2 == 0);
+ break;
+ default:
+ $min_match = TRUE;
+ $max_match = FALSE;
+ }
+
+ if ($min_match && $max_match) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ * Helper function to round minutes and seconds to requested value.
+ */
+function date_increment_round(&$date, $increment) {
+ // Round minutes and seconds, if necessary.
+ if (is_object($date) && $increment > 1) {
+ $day = intval(date_format($date, 'j'));
+ $hour = intval(date_format($date, 'H'));
+ $second = intval(round(intval(date_format($date, 's')) / $increment) * $increment);
+ $minute = intval(date_format($date, 'i'));
+ if ($second == 60) {
+ $minute += 1;
+ $second = 0;
+ }
+ $minute = intval(round($minute / $increment) * $increment);
+ if ($minute == 60) {
+ $hour += 1;
+ $minute = 0;
+ }
+ date_time_set($date, $hour, $minute, $second);
+ if ($hour == 24) {
+ $day += 1;
+ $hour = 0;
+ $year = date_format($date, 'Y');
+ $month = date_format($date, 'n');
+ date_date_set($date, $year, $month, $day);
+ }
+ }
+ return $date;
+}
+
+/**
+ * Return the nested form elements for a field by name.
+ * This can be used either to retrieve the entire sub-element
+ * for a field by name, no matter how deeply nested it is within
+ * fieldgroups or multigroups, or to find the multiple value
+ * sub-elements within a field element by name (i.e. 'value' or
+ * 'rrule'). You can also use this function to see if an item exists
+ * in a form (the return will be an empty array if it does not exist).
+ *
+ * The function returns an array of results. A field will generally
+ * only exist once in a form but the function can also be used to
+ * locate all the 'value' elements within a multiple value field,
+ * so the result is always returned as an array of values.
+ *
+ * For example, for a field named field_custom, the following will
+ * pluck out the form elements for this field from the node form,
+ * no matter how deeply it is nested within fieldgroups or fieldsets:
+ *
+ * $elements = content_get_nested_elements($node_form, 'field_custom');
+ *
+ * You can prefix the function with '&' to retrieve the element by
+ * reference to alter it directly:
+ *
+ * $elements = &content_get_nested_elements($form, 'field_custom');
+ * foreach ($elements as $element) {
+ * $element['#after_build'][] = 'my_field_afterbuild';
+ * }
+ *
+ * During the #after_build you could then do something like the
+ * following to alter each individual part of a multiple value field:
+ *
+ * $sub_elements = &content_get_nested_elements($element, 'value');
+ * foreach ($sub_elements as $sub_element) {
+ * $sub_element['#element_validate'][] = 'custom_validation';
+ * }
+ *
+ * @param $form
+ * The form array to search.
+ * @param $field_name
+ * The name or key of the form elements to return.
+ * @return
+ * An array of all matching form elements, returned by reference.
+ */
+function &date_get_nested_elements(&$form, $field_name) {
+ $elements = array();
+
+ foreach (element_children($form) as $key) {
+ if ($key === $field_name) {
+ $elements[] = &$form[$key];
+ }
+ elseif (is_array($form[$key])) {
+ $nested_form = &$form[$key];
+ if ($sub_elements = &date_get_nested_elements($nested_form, $field_name)) {
+ $elements = array_merge($elements, $sub_elements);
+ }
+ }
+ }
+
+ return $elements;
+}
diff --git a/sites/all/modules/date/date_api_elements.inc b/sites/all/modules/date/date_api_elements.inc
new file mode 100644
index 0000000..02e639a
--- /dev/null
+++ b/sites/all/modules/date/date_api_elements.inc
@@ -0,0 +1,634 @@
+ TRUE, '#tree' => TRUE,
+ '#date_timezone' => date_default_timezone_name(),
+ '#date_format' => variable_get('date_format_short', 'm/d/Y - H:i'),
+ '#date_text_parts' => array(),
+ '#date_increment' => 1,
+ '#date_year_range' => '-3:+3',
+ '#date_label_position' => 'above',
+ );
+ $type['date_select'] = array_merge($date_base, array(
+ '#process' => array('date_select_process'),
+ ));
+ $type['date_text'] = array_merge($date_base, array(
+ '#process' => array('date_text_process'),
+ ));
+ $type['date_timezone'] = array(
+ '#input' => TRUE, '#tree' => TRUE,
+ '#process' => array('date_timezone_process'),
+ );
+ return $type;
+}
+
+/**
+ * Create a timezone form element.
+ *
+ * @param array $element
+ * @return array
+ * the timezone form element
+ */
+function date_timezone_process($element, $edit, $form_state, $form) {
+ $element['#tree'] = TRUE;
+ $element['timezone'] = array(
+ '#type' => 'select',
+ '#title' => theme('date_part_label_timezone', 'select', $element),
+ '#default_value' => $element['#value'],
+ '#options' => date_timezone_names($element['#required']),
+ '#weight' => $element['#weight'],
+ '#required' => $element['#required'],
+ '#theme' => 'date_select_element',
+ );
+ if (isset($element['#element_validate'])) {
+ array_push($element['#element_validate'], 'date_timezone_validate');
+ }
+ else {
+ $element['#element_validate'] = array('date_timezone_validate');
+ }
+ // TODO This sometimes causes problems, do we need it?
+ //$element['#attributes'] = array('class' => 'date-timezone clear-block');
+ return $element;
+}
+
+/**
+ * Text date input form.
+ *
+ * Display all or part of a date in a single textfield.
+ *
+ * The exact parts displayed in the field are those in #date_granularity.
+ * The display of each part comes from #date_format.
+ *
+ * In regular FAPI processing $element['#value'] will contain a string
+ * value before the form is submitted, and an array during submission.
+ *
+ * In regular FAPI processing $edit is empty until the form is submitted
+ * when it will contain an array.
+ *
+ * Views widget processing now receives the same values as normal FAPI
+ * processing (that was not true in Views 1).
+ *
+ */
+function date_text_process($element, $edit, $form_state, $form) {
+ $date = NULL;
+ $granularity = date_format_order($element['#date_format']);
+
+ // We sometimes get $edit without $edit['date'] from
+ // Views exposed filters.
+ if (!empty($edit) && is_array($edit) && !empty($edit['date'])) {
+ $datetime = date_convert_from_custom($edit['date'], $element['#date_format']);
+ $date = date_make_date($datetime, $element['#date_timezone'], DATE_DATETIME, $granularity);
+ }
+ elseif (!empty($element['#value'])) {
+ $date = date_make_date($element['#value'], $element['#date_timezone'], DATE_DATETIME, $granularity);
+ }
+ $element['#tree'] = TRUE;
+
+ $element['date']['#type'] = 'textfield';
+ $element['date']['#weight'] = !empty($element['date']['#weight']) ? $element['date']['#weight'] : $element['#weight'];
+ $element['date']['#default_value'] = is_object($date) ? date_format_date($date , 'custom', $element['#date_format']) : '';
+ $element['date']['#attributes'] = array('class' => (isset($element['#attributes']['class']) ? $element['#attributes']['class'] : '') .' date-date');
+ $element['date']['#description'] = ' '. t('Format: @date', array('@date' => date_format_date(date_now(), 'custom', $element['#date_format'])));
+
+ // Keep the system from creating an error message for the sub-element.
+ // We'll set our own message on the parent element.
+ //$element['date']['#required'] = $element['#required'];
+ $element['date']['#theme'] = 'date_textfield_element';
+ if (isset($element['#element_validate'])) {
+ array_push($element['#element_validate'], 'date_text_validate');
+ }
+ else {
+ $element['#element_validate'] = array('date_text_validate');
+ }
+ if (!empty($element['#force_value'])) {
+ $element['date']['#value'] = $element['date']['#default_value'];
+ }
+ return $element;
+}
+
+/**
+ * Flexible date/time drop-down selector.
+ *
+ * Splits date into a collection of date and time sub-elements, one
+ * for each date part. Each sub-element can be either a textfield or a
+ * select, based on the value of ['#date_settings']['text_fields'].
+ *
+ * The exact parts displayed in the field are those in #date_granularity.
+ * The display of each part comes from ['#date_settings']['format'].
+ *
+ * In regular FAPI processing $element['#value'] will contain a string
+ * value before the form is submitted, and an array during submission.
+ *
+ * In regular FAPI processing $edit is empty until the form is submitted
+ * when it will contain an array.
+ *
+ * Views widget processing now receives the same values as normal FAPI
+ * processing (that was not true in Views 1).
+ *
+ */
+function date_select_process($element, $edit, $form_state, $form) {
+ $date = NULL;
+ $granularity = date_format_order($element['#date_format']);
+ if (!empty($edit)) {
+ $date = date_make_date($edit, $element['#date_timezone'], DATE_ARRAY, $granularity);
+ }
+ elseif (!empty($element['#value'])) {
+ $date = date_make_date($element['#value'], $element['#date_timezone'], DATE_DATETIME, $granularity);
+ }
+
+ $element['#tree'] = TRUE;
+ date_increment_round($date, $element['#date_increment']);
+ $element += (array) date_parts_element($element, $date, $element['#date_format']);
+
+ // Store a hidden value for all date parts not in the current display.
+ $granularity = date_format_order($element['#date_format']);
+ $formats = array('year' => 'Y', 'month' => 'n', 'day' => 'j', 'hour' => 'H', 'minute' => 'i', 'second' => 's');
+ foreach (date_nongranularity($granularity) as $field) {
+ if ($field != 'timezone') {
+ $element[$field] = array(
+ '#type' => 'value',
+ '#value' => 0,
+ );
+ }
+ }
+ if (isset($element['#element_validate'])) {
+ array_push($element['#element_validate'], 'date_select_validate');
+ }
+ else {
+ $element['#element_validate'] = array('date_select_validate');
+ }
+
+ return $element;
+}
+
+/**
+ * Create form elements for one or more date parts.
+ *
+ * Get the order of date elements from the provided format.
+ * If the format order omits any date parts in the granularity, alter the
+ * granularity array to match the format, then flip the $order array
+ * to get the position for each element. Then iterate through the
+ * elements and create a sub-form for each part.
+ *
+ * @param array $element
+ * @param object $date
+ * @param array $granularity
+ * @param string $format
+ * @return array
+ * the form array for the submitted date parts
+ */
+function date_parts_element($element, $date, $format) {
+ $granularity = date_format_order($format);
+ $sub_element = array('#granularity' => $granularity);
+ $order = array_flip($granularity);
+
+ $hours_format = strpos(strtolower($element['#date_format']), 'a') ? 'g': 'G';
+ $month_function = strpos($element['#date_format'], 'F') !== FALSE ? 'date_month_names' : 'date_month_names_abbr';
+ $count = 0;
+ $increment = min(intval($element['#date_increment']), 1);
+ foreach ($granularity as $field) {
+ // Allow empty value as option if date is not required
+ // or if empty value was provided as a starting point.
+ $part_required = ($element['#required'] && is_object($date)) ? TRUE : FALSE;
+ $part_type = in_array($field, $element['#date_text_parts']) ? 'textfield' : 'select';
+ $sub_element[$field] = array(
+ '#weight' => $order[$field],
+ '#required' => $element['#required'],
+ '#attributes' => array('class' => (isset($element['#attributes']['class']) ? $element['#attributes']['class'] : '') .' date-'. $field),
+ );
+ switch ($field) {
+ case 'year':
+ $range = date_range_years($element['#date_year_range'], $date);
+ $min_year = $range[0];
+ $max_year = $range[1];
+
+ $sub_element[$field]['#default_value'] = is_object($date) ? date_format($date, 'Y') : '';
+ if ($part_type == 'select') {
+ $sub_element[$field]['#options'] = drupal_map_assoc(date_years($min_year, $max_year, $part_required));
+ }
+ break;
+ case 'month':
+ $sub_element[$field]['#default_value'] = is_object($date) ? date_format($date, 'n') : '';
+ if ($part_type == 'select') {
+ $sub_element[$field]['#options'] = $month_function($part_required);
+ }
+ break;
+ case 'day':
+ $sub_element[$field]['#default_value'] = is_object($date) ? date_format($date, 'j') : '';
+ if ($part_type == 'select') {
+ $sub_element[$field]['#options'] = drupal_map_assoc(date_days($part_required));
+ }
+ break;
+ case 'hour':
+ $sub_element[$field]['#default_value'] = is_object($date) ? date_format($date, $hours_format) : '';
+ if ($part_type == 'select') {
+ $sub_element[$field]['#options'] = drupal_map_assoc(date_hours($hours_format, $part_required));
+ }
+ $sub_element[$field]['#prefix'] = theme('date_part_hour_prefix', $element);
+ break;
+ case 'minute':
+ $sub_element[$field]['#default_value'] = is_object($date) ? date_format($date, 'i') : '';
+ if ($part_type == 'select') {
+ $sub_element[$field]['#options'] = drupal_map_assoc(date_minutes('i', $part_required, $element['#date_increment']));
+ }
+ $sub_element[$field]['#prefix'] = theme('date_part_minsec_prefix', $element);
+ break;
+ case 'second':
+ $sub_element[$field]['#default_value'] = is_object($date) ? date_format($date, 's') : '';
+ if ($part_type == 'select') {
+ $sub_element[$field]['#options'] = drupal_map_assoc(date_seconds('s', $part_required, $element['#date_increment']));
+ }
+ $sub_element[$field]['#prefix'] = theme('date_part_minsec_prefix', $element);
+ break;
+ }
+
+ // Add handling for the date part label.
+ $label = theme('date_part_label_'. $field, $part_type, $element);
+ if (in_array($field, $element['#date_text_parts'])) {
+ $sub_element[$field]['#type'] = 'textfield';
+ $sub_element[$field]['#theme'] = 'date_textfield_element';
+ $sub_element[$field]['#size'] = 7;
+ if ($element['#date_label_position'] == 'within') {
+ if (is_array($sub_element[$field]['#options'])) {
+ $sub_element[$field]['#options'] = array(
+ '-'. $label => '-'. $label) + $sub_element[$field]['#options'];
+ }
+ if (empty($sub_element[$field]['#default_value'])) {
+ $sub_element[$field]['#default_value'] = '-'. $label;
+ }
+ }
+ elseif ($element['#date_label_position'] != 'none') {
+ $sub_element[$field]['#title'] = $label;
+ }
+ }
+ else {
+ $sub_element[$field]['#type'] = 'select';
+ $sub_element[$field]['#theme'] = 'date_select_element';
+ if ($element['#date_label_position'] == 'within') {
+ $sub_element[$field]['#options'] = array(
+ '' => '-'. $label) + $sub_element[$field]['#options'];
+ }
+ elseif ($element['#date_label_position'] != 'none') {
+ $sub_element[$field]['#title'] = $label;
+ }
+ }
+
+ // Views exposed filters are treated as submitted even if not,
+ // so force the #default value in that case. Make sure we set
+ // a default that is in the option list.
+ if (!empty($element['#force_value'])) {
+ $options = $sub_element[$field]['#options'];
+ $default = !empty($sub_element[$field]['#default_value']) ? $sub_element[$field]['#default_value'] : array_shift($options);
+ $sub_element[$field]['#value'] = $default;
+ }
+ }
+
+ if (($hours_format == 'g' || $hours_format == 'h') && date_has_time($granularity)) {
+ $sub_element['ampm'] = array(
+ '#type' => 'select',
+ '#default_value' => is_object($date) ? (date_format($date, 'G') >= 12 ? 'pm' : 'am') : '',
+ '#options' => drupal_map_assoc(date_ampm()),
+ '#weight' => 8,
+ '#attributes' => array('class' => 'date-ampm'),
+ );
+ if ($element['#date_label_position'] == 'within') {
+ $sub_element['ampm']['#options'] = array('' => '-'. theme('date_part_label_ampm', 'ampm', $element)) + $sub_element['ampm']['#options'];
+ }
+ elseif ($element['#date_label_position'] != 'none') {
+ $sub_element['ampm']['#title'] = theme('date_part_label_ampm', 'ampm', $element);
+ }
+ }
+
+ return $sub_element;
+}
+
+/**
+ * Validation function for date selector.
+ *
+ * When used as a Views widget, the validation step always gets triggered,
+ * even with no form submission. Before form submission $element['#value']
+ * contains a string, after submission it contains an array.
+ *
+ */
+function date_select_validate($element, &$form_state) {
+ if (is_string($element['#value'])) {
+ return;
+ }
+ // Strip field labels out of the results.
+ foreach ($element['#value'] as $field => $field_value) {
+ if (drupal_substr($field_value, 0, 1) == '-') {
+ $element['#value'][$field] = '';
+ }
+ }
+
+ $error_field = implode('][', $element['#parents']);
+ $errors = array();
+ $label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
+
+ if (in_array('year', $element['#granularity']) && ($element['#required'] || !empty($element['#value']['year']))) {
+ if ($element['#value']['year'] < variable_get('date_min_year', 1) || $element['#value']['year'] > variable_get('date_max_year', 4000)) {
+ $errors[] = t('The year must be a number between %min and %max.', array(
+ '%min' => variable_get('date_min_year', 1), '%max' => variable_get('date_max_year', 4000)));
+ }
+ else {
+ $year = $element['#value']['year'];
+ }
+ }
+ if (in_array('month', $element['#granularity']) && ($element['#required'] || !empty($element['#value']['month']))) {
+ if ($element['#value']['month'] < 1 || $element['#value']['month'] > 12) {
+ $errors[] = t('The month must be a number between 1 and 12.');
+ }
+ else {
+ $month = $element['#value']['month'];
+ }
+ }
+ if (in_array('day', $element['#granularity']) && ($element['#required'] || !empty($element['#value']['day']))) {
+ $min = 1;
+ $max = isset($year) && isset($month) ? date_days_in_month($year, $month) : 31;
+ if ($element['#value']['day'] < $min || $element['#value']['day'] > $max) {
+ $errors[] = t('The day must be a number between !min and !max.', array('!min' => $min, '!max' => $max));
+ }
+ }
+ if (in_array('hour', $element['#granularity']) && ($element['#required'] || !empty($element['#value']['hour']))) {
+ $min = isset($element['#value']['ampm']) ? 1 : 0;
+ $max = isset($element['#value']['ampm']) ? 12 : 23;
+ if ($element['#value']['hour'] < $min || $element['#value']['hour'] > $max) {
+ $errors[] = t('The hour must be a number between !min and !max.', array('!min' => $min, '!max' => $max));
+ }
+ }
+ if (in_array('minute', $element['#granularity']) && ($element['#required'] || !empty($element['#value']['minute']))) {
+ $min = 0;
+ $max = 59;
+ if ($element['#value']['minute'] < $min || $element['#value']['minute'] > $max) {
+ $errors[] = t('The minute must be a number between !min and !max.', array('!min' => $min, '!max' => $max));
+ }
+ }
+ if (in_array('second', $element['#granularity']) && ($element['#required'] || !empty($element['#value']['second']))) {
+ $min = 0;
+ $max = 59;
+ if ($element['#value']['second'] < $min || $element['#value']['second'] > $max) {
+ $errors[] = t('The second must be a number between !min and !max.', array('!min' => $min, '!max' => $max));
+ }
+ }
+ if (isset($element['#value']['ampm'])) {
+ if ($element['#value']['ampm'] == 'pm' && $element['#value']['hour'] < 12) {
+ $element['#value']['hour'] += 12;
+ }
+ elseif ($element['#value']['ampm'] == 'am' && $element['#value']['hour'] == 12) {
+ $element['#value']['hour'] -= 12;
+ }
+ }
+ $value = date_select_input_value($element);
+ if (empty($value) && empty($errors) && $element['#required']) {
+ $errors[] = t('A valid value is required.');
+ }
+ if (!empty($errors)) {
+ array_unshift($errors, t('Field %field has errors.', array('%field' => $label)));
+ form_set_error($error_field, implode(' ', $errors));
+ }
+ // If there are no errors and the value is valid, set it.
+ if (empty($errors) && !empty($value)) {
+ form_set_value($element, $value, $form_state);
+ }
+ else {
+ form_set_value($element, NULL, $form_state);
+ }
+}
+
+/**
+ * Helper function for extracting a date value out of user input.
+ */
+function date_select_input_value($element) {
+ $granularity = date_format_order($element['#date_format']);
+ if (date_is_valid($element['#value'], DATE_ARRAY, $granularity)) {
+ // Use fuzzy_datetime here to be sure year-only dates
+ // aren't inadvertantly shifted to the wrong year by trying
+ // to save '2009-00-00 00:00:00'.
+ return date_fuzzy_datetime(date_convert($element['#value'], DATE_ARRAY, DATE_DATETIME));
+ }
+ return NULL;
+}
+
+/**
+ * Validation for text input.
+ *
+ * When used as a Views widget, the validation step always gets triggered,
+ * even with no form submission. Before form submission $element['#value']
+ * contains a string, after submission it contains an array.
+ *
+ */
+function date_text_validate($element, &$form_state) {
+ if (is_string($element['#value'])) {
+ return;
+ }
+ $parents = $element['#parents'];
+ $label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
+ $value = date_text_input_value($element);
+
+ if (empty($value) && !empty($element['#required'])) {
+ form_error($element, t('A valid date is required for %title.', array('%title' => $label)));
+ }
+ elseif (empty($value) && !empty($element['#value']['date'])) {
+ form_error($element, t('%title is invalid.', array('%title' => $label)));
+ }
+ elseif (!empty($value)) {
+ form_set_value($element, $value, $form_state);
+ }
+}
+
+/**
+ * Helper function for extracting a date value out of user input.
+ */
+function date_text_input_value($element) {
+ $form_values = $element['#value'];
+ $granularity = date_format_order($element['#date_format']);
+ $input = $form_values['date'];
+ if (!$element['#required'] && trim($input) == '') return NULL;
+
+ $value = date_limit_value(date_convert_from_custom($input, $element['#date_format']), $granularity);
+
+ // If it creates a valid date, use it.
+ if (date_is_valid($value, DATE_DATETIME, $granularity)) {
+ return $value;
+ }
+ // TODO come back and try to find a way to use strtotime to guess
+ // a valid value. Previous attempts to do it were too forgiving and
+ // invalid input was just silently converted to 'now'.
+ // See http://drupal.org/node/265076.
+
+ return NULL;
+}
+
+/**
+ * Validation for timezone input
+ *
+ * Move the timezone value from the nested field back to the original field.
+ */
+function date_timezone_validate($element, &$form_state) {
+ form_set_value($element, $element['#value']['timezone'], $form_state);
+}
+
+/**
+ * Convert a date input in a custom format to a standard date type
+ *
+ * Handles conversion of translated month names (i.e. turns t('Mar') or
+ * t('March') into 3). Also properly handles dates input in European style
+ * short formats, like DD/MM/YYYY. Works by parsing the format string
+ * to create a regex that can be used on the input value.
+ *
+ * The original code to do this was created by Yves Chedemois (yched).
+ *
+ * @param string $date
+ * a date value
+ * @param string $format
+ * a date format string that describes the format of the input value
+ * @return mixed
+ * input value converted to a DATE_DATETIME value
+ */
+function date_convert_from_custom($date, $format) {
+ $array = date_format_patterns();
+ foreach ($array as $key => $value) {
+ $patterns[] = "`(^|[^\\\\\\\\])". $key ."`"; // the letter with no preceding '\'
+ $repl1[] = '${1}(.)'; // a single character
+ $repl2[] = '${1}('. $value .')'; // the
+ }
+ $patterns[] = "`\\\\\\\\([". implode(array_keys($array)) ."])`";
+ $repl1[] = '${1}';
+ $repl2[] = '${1}';
+
+ $format_regexp = preg_quote($format);
+
+ // extract letters
+ $regex1 = preg_replace($patterns, $repl1, $format_regexp, 1);
+ $regex1 = str_replace('A', '(.)', $regex1);
+ $regex1 = str_replace('a', '(.)', $regex1);
+ preg_match('`^'. $regex1 .'$`', stripslashes($format), $letters);
+ array_shift($letters);
+
+ // extract values
+ $regex2 = preg_replace($patterns, $repl2, $format_regexp, 1);
+ $regex2 = str_replace('A', '(AM|PM)', $regex2);
+ $regex2 = str_replace('a', '(am|pm)', $regex2);
+ preg_match('`^'. $regex2 .'$`', $date, $values);
+ array_shift($values);
+
+ // if we did not find all the values for the patterns in the format, abort
+ if (count($letters) != count($values)) {
+ return NULL;
+ }
+ $final_date = array('hour' => 0, 'minute' => 0, 'second' => 0,
+ 'month' => 0, 'day' => 0, 'year' => 0);
+ foreach ($letters as $i => $letter) {
+ $value = $values[$i];
+ switch ($letter) {
+ case 'd':
+ case 'j':
+ $final_date['day'] = intval($value);
+ break;
+ case 'n':
+ case 'm':
+ $final_date['month'] = intval($value);
+ break;
+ case 'F':
+ $array_month_long = array_flip(date_month_names());
+ $final_date['month'] = $array_month_long[$value];
+ break;
+ case 'M':
+ $array_month = array_flip(date_month_names_abbr());
+ $final_date['month'] = $array_month[$value];
+ break;
+ case 'Y':
+ case 'y':
+ $year = $value;
+ // if no century, we add the current one ("06" => "2006")
+ $final_date['year'] = str_pad($year, 4, drupal_substr(date("Y"), 0, 2), STR_PAD_LEFT);
+ break;
+ case 'a':
+ case 'A':
+ $ampm = strtolower($value);
+ break;
+ case 'g':
+ case 'h':
+ case 'G':
+ case 'H':
+ $final_date['hour'] = intval($value);
+ break;
+ case 'i':
+ $final_date['minute'] = intval($value);
+ break;
+ case 's':
+ $final_date['second'] = intval($value);
+ break;
+ case 'U':
+ return date_convert($value, DATE_UNIX, DATE_DATETIME);
+ break;
+ }
+ }
+ if (isset($ampm) && $ampm == 'pm' && $final_date['hour'] < 12) {
+ $final_date['hour'] += 12;
+ }
+ elseif (isset($ampm) && $ampm == 'am' && $final_date['hour'] == 12) {
+ $final_date['hour'] -= 12;
+ }
+ // Don't test for valid date, we might use this to extract
+ // incomplete date part info from user input.
+ return date_convert($final_date, DATE_ARRAY, DATE_DATETIME);
+}
\ No newline at end of file
diff --git a/sites/all/modules/date/date_api_formats_list.inc b/sites/all/modules/date/date_api_formats_list.inc
new file mode 100644
index 0000000..ea033f9
--- /dev/null
+++ b/sites/all/modules/date/date_api_formats_list.inc
@@ -0,0 +1,192 @@
+ 'short',
+ 'format' => 'Y-m-d H:i',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'short',
+ 'format' => 'm/d/Y - H:i',
+ 'locales' => array('en-us'),
+ );
+ $formats[] = array(
+ 'type' => 'short',
+ 'format' => 'd/m/Y - H:i',
+ 'locales' => array('en-gb', 'en-hk', 'en-ie', 'el-gr', 'es-es', 'fr-be', 'fr-fr', 'fr-lu', 'it-it', 'nl-be', 'pt-pt'),
+ );
+ $formats[] = array(
+ 'type' => 'short',
+ 'format' => 'Y/m/d - H:i',
+ 'locales' => array('en-ca', 'fr-ca', 'no-no', 'sv-se'),
+ );
+ $formats[] = array(
+ 'type' => 'short',
+ 'format' => 'd.m.Y - H:i',
+ 'locales' => array('de-ch', 'de-de', 'de-lu', 'fi-fi', 'fr-ch', 'is-is', 'pl-pl', 'ro-ro', 'ru-ru'),
+ );
+ $formats[] = array(
+ 'type' => 'short',
+ 'format' => 'm/d/Y - g:ia',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'short',
+ 'format' => 'd/m/Y - g:ia',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'short',
+ 'format' => 'Y/m/d - g:ia',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'short',
+ 'format' => 'M j Y - H:i',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'short',
+ 'format' => 'j M Y - H:i',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'short',
+ 'format' => 'Y M j - H:i',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'short',
+ 'format' => 'M j Y - g:ia',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'short',
+ 'format' => 'j M Y - g:ia',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'short',
+ 'format' => 'Y M j - g:ia',
+ 'locales' => array(),
+ );
+
+ // Medium date formats.
+ $formats[] = array(
+ 'type' => 'medium',
+ 'format' => 'D, Y-m-d H:i',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'medium',
+ 'format' => 'D, m/d/Y - H:i',
+ 'locales' => array('en-us'),
+ );
+ $formats[] = array(
+ 'type' => 'medium',
+ 'format' => 'D, d/m/Y - H:i',
+ 'locales' => array('en-gb', 'en-hk', 'en-ie', 'el-gr', 'es-es', 'fr-be', 'fr-fr', 'fr-lu', 'it-it', 'nl-be', 'pt-pt'),
+ );
+ $formats[] = array(
+ 'type' => 'medium',
+ 'format' => 'D, Y/m/d - H:i',
+ 'locales' => array('en-ca', 'fr-ca', 'no-no', 'sv-se'),
+ );
+ $formats[] = array(
+ 'type' => 'medium',
+ 'format' => 'F j, Y - H:i',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'medium',
+ 'format' => 'j F, Y - H:i',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'medium',
+ 'format' => 'Y, F j - H:i',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'medium',
+ 'format' => 'D, m/d/Y - g:ia',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'medium',
+ 'format' => 'D, d/m/Y - g:ia',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'medium',
+ 'format' => 'D, Y/m/d - g:ia',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'medium',
+ 'format' => 'F j, Y - g:ia',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'medium',
+ 'format' => 'j F Y - g:ia',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'medium',
+ 'format' => 'Y, F j - g:ia',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'medium',
+ 'format' => 'j. F Y - G:i',
+ 'locales' => array(),
+ );
+
+ // Long date formats.
+ $formats[] = array(
+ 'type' => 'long',
+ 'format' => 'l, F j, Y - H:i',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'long',
+ 'format' => 'l, j F, Y - H:i',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'long',
+ 'format' => 'l, Y, F j - H:i',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'long',
+ 'format' => 'l, F j, Y - g:ia',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'long',
+ 'format' => 'l, j F Y - g:ia',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'long',
+ 'format' => 'l, Y, F j - g:ia',
+ 'locales' => array(),
+ );
+ $formats[] = array(
+ 'type' => 'long',
+ 'format' => 'l, j. F Y - G:i',
+ 'locales' => array(),
+ );
+
+ return $formats;
+}
diff --git a/sites/all/modules/date/date_api_ical.inc b/sites/all/modules/date/date_api_ical.inc
new file mode 100644
index 0000000..2aa2e46
--- /dev/null
+++ b/sites/all/modules/date/date_api_ical.inc
@@ -0,0 +1,802 @@
+ date in YYYY-MM-DD HH:MM format, not timezone adjusted
+ * 'all_day' => whether this is an all-day event
+ * 'tz' => the timezone of the date, could be blank for absolute
+ * times that should get no timezone conversion.
+ *
+ * Exception dates can have muliple values and are returned as arrays
+ * like the above for each exception date.
+ *
+ * Most other properties are returned as PROPERTY => VALUE.
+ *
+ * Each item in the VCALENDAR will return an array like:
+ * [0] => Array (
+ * [TYPE] => VEVENT
+ * [UID] => 104
+ * [SUMMARY] => An example event
+ * [URL] => http://example.com/node/1
+ * [DTSTART] => Array (
+ * [datetime] => 1997-09-07 09:00:00
+ * [all_day] => 0
+ * [tz] => US/Eastern
+ * )
+ * [DTEND] => Array (
+ * [datetime] => 1997-09-07 11:00:00
+ * [all_day] => 0
+ * [tz] => US/Eastern
+ * )
+ * [RRULE] => Array (
+ * [FREQ] => Array (
+ * [0] => MONTHLY
+ * )
+ * [BYDAY] => Array (
+ * [0] => 1SU
+ * [1] => -1SU
+ * )
+ * )
+ * [EXDATE] => Array (
+ * [0] = Array (
+ * [datetime] => 1997-09-21 09:00:00
+ * [all_day] => 0
+ * [tz] => US/Eastern
+ * )
+ * [1] = Array (
+ * [datetime] => 1997-10-05 09:00:00
+ * [all_day] => 0
+ * [tz] => US/Eastern
+ * )
+ * )
+ * [RDATE] => Array (
+ * [0] = Array (
+ * [datetime] => 1997-09-21 09:00:00
+ * [all_day] => 0
+ * [tz] => US/Eastern
+ * )
+ * [1] = Array (
+ * [datetime] => 1997-10-05 09:00:00
+ * [all_day] => 0
+ * [tz] => US/Eastern
+ * )
+ * )
+ * )
+ *
+ * @todo
+ * figure out how to handle this if subgroups are nested,
+ * like a VALARM nested inside a VEVENT.
+ *
+ * @param string $filename
+ * Location (local or remote) of a valid iCalendar file.
+ *
+ * @return array
+ * An array with all the elements from the ical.
+ */
+function date_ical_import($filename) {
+ // Fetch the iCal data. If file is a URL, use drupal_http_request. fopen
+ // isn't always configured to allow network connections.
+ if (substr($filename, 0, 4) == 'http') {
+ // Fetch the ical data from the specified network location.
+ $icaldatafetch = drupal_http_request($filename);
+ // Check the return result.
+ if ($icaldatafetch->error) {
+ watchdog('date ical', 'HTTP Request Error importing %filename: @error', array('%filename' => $filename, '@error' => $icaldatafetch->error));
+ return FALSE;
+ }
+ // Break the return result into one array entry per lines.
+ $icaldatafolded = explode("\n", $icaldatafetch->data);
+ }
+ else {
+ $icaldatafolded = @file($filename, FILE_IGNORE_NEW_LINES);
+ if ($icaldatafolded === FALSE) {
+ watchdog('date ical', 'Failed to open file: %filename', array('%filename' => $filename));
+ return FALSE;
+ }
+ }
+ // Verify this is iCal data.
+ if (trim($icaldatafolded[0]) != 'BEGIN:VCALENDAR') {
+ watchdog('date ical', 'Invalid calendar file: %filename', array('%filename' => $filename));
+ return FALSE;
+ }
+ return date_ical_parse($icaldatafolded);
+}
+
+/**
+ * Returns an array of iCalendar information from an iCalendar file.
+ *
+ * As date_ical_import() but different param.
+ *
+ * @param array $icaldatafolded
+ * An array of lines from an ical feed.
+ *
+ * @return array
+ * An array with all the elements from the ical.
+ */
+function date_ical_parse($icaldatafolded = array()) {
+ $items = array();
+
+ // Verify this is iCal data.
+ if (trim($icaldatafolded[0]) != 'BEGIN:VCALENDAR') {
+ watchdog('date ical', 'Invalid calendar file.');
+ return FALSE;
+ }
+
+ // "Unfold" wrapped lines.
+ $icaldata = array();
+ foreach ($icaldatafolded as $line) {
+ $out = array();
+ // See if this looks like the beginning of a new property or value. If not,
+ // it is a continuation of the previous line. The regex is to ensure that
+ // wrapped QUOTED-PRINTABLE data is kept intact.
+ if (!preg_match('/([A-Z]+)[:;](.*)/', $line, $out)) {
+ // Trim up to 1 leading space from wrapped line per iCalendar standard.
+ $line = array_pop($icaldata) . (ltrim(substr($line, 0, 1)) . substr($line, 1));
+ }
+ $icaldata[] = $line;
+ }
+ unset($icaldatafolded);
+
+ // Parse the iCal information.
+ $parents = array();
+ $subgroups = array();
+ $vcal = '';
+ foreach ($icaldata as $line) {
+ $line = trim($line);
+ $vcal .= $line . "\n";
+ // Deal with begin/end tags separately.
+ if (preg_match('/(BEGIN|END):V(\S+)/', $line, $matches)) {
+ $closure = $matches[1];
+ $type = 'V' . $matches[2];
+ if ($closure == 'BEGIN') {
+ array_push($parents, $type);
+ array_push($subgroups, array());
+ }
+ elseif ($closure == 'END') {
+ end($subgroups);
+ $subgroup = &$subgroups[key($subgroups)];
+ switch ($type) {
+ case 'VCALENDAR':
+ if (prev($subgroups) == FALSE) {
+ $items[] = array_pop($subgroups);
+ }
+ else {
+ $parent[array_pop($parents)][] = array_pop($subgroups);
+ }
+ break;
+ // Add the timezones in with their index their TZID.
+ case 'VTIMEZONE':
+ $subgroup = end($subgroups);
+ $id = $subgroup['TZID'];
+ unset($subgroup['TZID']);
+
+ // Append this subgroup onto the one above it.
+ prev($subgroups);
+ $parent = &$subgroups[key($subgroups)];
+
+ $parent[$type][$id] = $subgroup;
+
+ array_pop($subgroups);
+ array_pop($parents);
+ break;
+ // Do some fun stuff with durations and all_day events and then append
+ // to parent.
+ case 'VEVENT':
+ case 'VALARM':
+ case 'VTODO':
+ case 'VJOURNAL':
+ case 'VVENUE':
+ case 'VFREEBUSY':
+ default:
+ // Can't be sure whether DTSTART is before or after DURATION, so
+ // parse DURATION at the end.
+ if (isset($subgroup['DURATION'])) {
+ date_ical_parse_duration($subgroup, 'DURATION');
+ }
+ // Add a top-level indication for the 'All day' condition. Leave it
+ // in the individual date components, too, so it is always available
+ // even when you are working with only a portion of the VEVENT
+ // array, like in Feed API parsers.
+ $subgroup['all_day'] = FALSE;
+
+ // iCal spec states 'The "DTEND" property for a "VEVENT" calendar
+ // component specifies the non-inclusive end of the event'. Adjust
+ // multi-day events to remove the extra day because the Date code
+ // assumes the end date is inclusive.
+ if (!empty($subgroup['DTEND']) && (!empty($subgroup['DTEND']['all_day']))) {
+ // Make the end date one day earlier.
+ $date = date_make_date($subgroup['DTEND']['datetime'] . ' 00:00:00', $subgroup['DTEND']['tz']);
+ date_modify($date, '-1 day');
+ $subgroup['DTEND']['datetime'] = date_format($date, 'Y-m-d');
+ }
+ // If a start datetime is defined AND there is no definition for
+ // the end datetime THEN make the end datetime equal the start
+ // datetime and if it is an all day event define the entire event
+ // as a single all day event.
+ if (!empty($subgroup['DTSTART']) &&
+ (empty($subgroup['DTEND']) && empty($subgroup['RRULE']) && empty($subgroup['RRULE']['COUNT']))) {
+ $subgroup['DTEND'] = $subgroup['DTSTART'];
+ }
+ // Add this element to the parent as an array under the component
+ // name.
+ if (!empty($subgroup['DTSTART']['all_day'])) {
+ $subgroup['all_day'] = TRUE;
+ }
+ // Add this element to the parent as an array under the
+ prev($subgroups);
+ $parent = &$subgroups[key($subgroups)];
+
+ $parent[$type][] = $subgroup;
+
+ array_pop($subgroups);
+ array_pop($parents);
+ break;
+ }
+ }
+ }
+ // Handle all other possibilities.
+ else {
+ // Grab current subgroup.
+ end($subgroups);
+ $subgroup = &$subgroups[key($subgroups)];
+
+ // Split up the line into nice pieces for PROPERTYNAME,
+ // PROPERTYATTRIBUTES, and PROPERTYVALUE.
+ preg_match('/([^;:]+)(?:;([^:]*))?:(.+)/', $line, $matches);
+ $name = !empty($matches[1]) ? strtoupper(trim($matches[1])) : '';
+ $field = !empty($matches[2]) ? $matches[2] : '';
+ $data = !empty($matches[3]) ? $matches[3] : '';
+ $parse_result = '';
+ switch ($name) {
+ // Keep blank lines out of the results.
+ case '':
+ break;
+
+ // Lots of properties have date values that must be parsed out.
+ case 'CREATED':
+ case 'LAST-MODIFIED':
+ case 'DTSTART':
+ case 'DTEND':
+ case 'DTSTAMP':
+ case 'FREEBUSY':
+ case 'DUE':
+ case 'COMPLETED':
+ $parse_result = date_ical_parse_date($field, $data);
+ break;
+
+ case 'EXDATE':
+ case 'RDATE':
+ $parse_result = date_ical_parse_exceptions($field, $data);
+ break;
+
+ case 'TRIGGER':
+ // A TRIGGER can either be a date or in the form -PT1H.
+ if (!empty($field)) {
+ $parse_result = date_ical_parse_date($field, $data);
+ }
+ else {
+ $parse_result = array('DATA' => $data);
+ }
+ break;
+
+ case 'DURATION':
+ // Can't be sure whether DTSTART is before or after DURATION in
+ // the VEVENT, so store the data and parse it at the end.
+ $parse_result = array('DATA' => $data);
+ break;
+
+ case 'RRULE':
+ case 'EXRULE':
+ $parse_result = date_ical_parse_rrule($field, $data);
+ break;
+
+ case 'STATUS':
+ case 'SUMMARY':
+ case 'DESCRIPTION':
+ $parse_result = date_ical_parse_text($field, $data);
+ break;
+
+ case 'LOCATION':
+ $parse_result = date_ical_parse_location($field, $data);
+ break;
+
+ // For all other properties, just store the property and the value.
+ // This can be expanded on in the future if other properties should
+ // be given special treatment.
+ default:
+ $parse_result = $data;
+ break;
+ }
+
+ // Store the result of our parsing.
+ $subgroup[$name] = $parse_result;
+ }
+ }
+ return $items;
+}
+
+/**
+ * Parses a ical date element.
+ *
+ * Possible formats to parse include:
+ * PROPERTY:YYYYMMDD[T][HH][MM][SS][Z]
+ * PROPERTY;VALUE=DATE:YYYYMMDD[T][HH][MM][SS][Z]
+ * PROPERTY;VALUE=DATE-TIME:YYYYMMDD[T][HH][MM][SS][Z]
+ * PROPERTY;TZID=XXXXXXXX;VALUE=DATE:YYYYMMDD[T][HH][MM][SS]
+ * PROPERTY;TZID=XXXXXXXX:YYYYMMDD[T][HH][MM][SS]
+ *
+ * The property and the colon before the date are removed in the import
+ * process above and we are left with $field and $data.
+ *
+ * @param string $field
+ * The text before the colon and the date, i.e.
+ * ';VALUE=DATE:', ';VALUE=DATE-TIME:', ';TZID='
+ * @param string $data
+ * The date itself, after the colon, in the format YYYYMMDD[T][HH][MM][SS][Z]
+ * 'Z', if supplied, means the date is in UTC.
+ *
+ * @return array
+ * $items array, consisting of:
+ * 'datetime' => date in YYYY-MM-DD HH:MM format, not timezone adjusted
+ * 'all_day' => whether this is an all-day event with no time
+ * 'tz' => the timezone of the date, could be blank if the ical
+ * has no timezone; the ical specs say no timezone
+ * conversion should be done if no timezone info is
+ * supplied
+ * @todo
+ * Another option for dates is the format PROPERTY;VALUE=PERIOD:XXXX. The
+ * period may include a duration, or a date and a duration, or two dates, so
+ * would have to be split into parts and run through date_ical_parse_date()
+ * and date_ical_parse_duration(). This is not commonly used, so ignored for
+ * now. It will take more work to figure how to support that.
+ */
+function date_ical_parse_date($field, $data) {
+
+ $items = array('datetime' => '', 'all_day' => '', 'tz' => '');
+ if (empty($data)) {
+ return $items;
+ }
+ // Make this a little more whitespace independent.
+ $data = trim($data);
+
+ // Turn the properties into a nice indexed array of
+ // array(PROPERTYNAME => PROPERTYVALUE);
+ $field_parts = preg_split('/[;:]/', $field);
+ $properties = array();
+ foreach ($field_parts as $part) {
+ if (strpos($part, '=') !== FALSE) {
+ $tmp = explode('=', $part);
+ $properties[$tmp[0]] = $tmp[1];
+ }
+ }
+
+ // Make this a little more whitespace independent.
+ $data = trim($data);
+
+ // Record if a time has been found.
+ $has_time = FALSE;
+
+ // If a format is specified, parse it according to that format.
+ if (isset($properties['VALUE'])) {
+ switch ($properties['VALUE']) {
+ case 'DATE':
+ preg_match(DATE_REGEX_ICAL_DATE, $data, $regs);
+ // Date.
+ $datetime = date_pad($regs[1]) . '-' . date_pad($regs[2]) . '-' . date_pad($regs[3]);
+ break;
+ case 'DATE-TIME':
+ preg_match(DATE_REGEX_ICAL_DATETIME, $data, $regs);
+ // Date.
+ $datetime = date_pad($regs[1]) . '-' . date_pad($regs[2]) . '-' . date_pad($regs[3]);
+ // Time.
+ $datetime .= ' ' . date_pad($regs[4]) . ':' . date_pad($regs[5]) . ':' . date_pad($regs[6]);
+ $has_time = TRUE;
+ break;
+ }
+ }
+ // If no format is specified, attempt a loose match.
+ else {
+ preg_match(DATE_REGEX_LOOSE, $data, $regs);
+ if (!empty($regs) && count($regs) > 2) {
+ // Date.
+ $datetime = date_pad($regs[1]) . '-' . date_pad($regs[2]) . '-' . date_pad($regs[3]);
+ if (isset($regs[4])) {
+ $has_time = TRUE;
+ // Time.
+ $datetime .= ' ' . (!empty($regs[5]) ? date_pad($regs[5]) : '00') .
+ ':' . (!empty($regs[6]) ? date_pad($regs[6]) : '00') .
+ ':' . (!empty($regs[7]) ? date_pad($regs[7]) : '00');
+ }
+ }
+ }
+
+ // Use timezone if explicitly declared.
+ if (isset($properties['TZID'])) {
+ $tz = $properties['TZID'];
+ // Fix alternatives like US-Eastern which should be US/Eastern.
+ $tz = str_replace('-', '/', $tz);
+ // Unset invalid timezone names.
+ module_load_include('install', 'date_timezone');
+ $tz = _date_timezone_replacement($tz);
+ if (!date_timezone_is_valid($tz)) {
+ $tz = '';
+ }
+ }
+ // If declared as UTC with terminating 'Z', use that timezone.
+ elseif (strpos($data, 'Z') !== FALSE) {
+ $tz = 'UTC';
+ }
+ // Otherwise this date is floating.
+ else {
+ $tz = '';
+ }
+
+ $items['datetime'] = $datetime;
+ $items['all_day'] = $has_time ? FALSE : TRUE;
+ $items['tz'] = $tz;
+ return $items;
+}
+
+/**
+ * Parse an ical repeat rule.
+ *
+ * @return array
+ * Array in the form of PROPERTY => array(VALUES)
+ * PROPERTIES include FREQ, INTERVAL, COUNT, BYDAY, BYMONTH, BYYEAR, UNTIL
+ */
+function date_ical_parse_rrule($field, $data) {
+ $data = preg_replace("/RRULE.*:/", '', $data);
+ $items = array('DATA' => $data);
+ $rrule = explode(';', $data);
+ foreach ($rrule as $key => $value) {
+ $param = explode('=', $value);
+ // Must be some kind of invalid data.
+ if (count($param) != 2) {
+ continue;
+ }
+ if ($param[0] == 'UNTIL') {
+ $values = date_ical_parse_date('', $param[1]);
+ }
+ else {
+ $values = explode(',', $param[1]);
+ }
+ // Treat items differently if they have multiple or single values.
+ if (in_array($param[0], array('FREQ', 'INTERVAL', 'COUNT', 'WKST'))) {
+ $items[$param[0]] = $param[1];
+ }
+ else {
+ $items[$param[0]] = $values;
+ }
+ }
+ return $items;
+}
+
+/**
+ * Parse exception dates (can be multiple values).
+ *
+ * @return array
+ * an array of date value arrays.
+ */
+function date_ical_parse_exceptions($field, $data) {
+ $data = str_replace($field . ':', '', $data);
+ $items = array('DATA' => $data);
+ $ex_dates = explode(',', $data);
+ foreach ($ex_dates as $ex_date) {
+ $items[] = date_ical_parse_date('', $ex_date);
+ }
+ return $items;
+}
+
+/**
+ * Parses the duration of the event.
+ *
+ * Example:
+ * DURATION:PT1H30M
+ * DURATION:P1Y2M
+ *
+ * @param array $subgroup
+ * Array of other values in the vevent so we can check for DTSTART.
+ */
+function date_ical_parse_duration(&$subgroup, $field = 'DURATION') {
+ $items = $subgroup[$field];
+ $data = $items['DATA'];
+ preg_match('/^P(\d{1,4}[Y])?(\d{1,2}[M])?(\d{1,2}[W])?(\d{1,2}[D])?([T]{0,1})?(\d{1,2}[H])?(\d{1,2}[M])?(\d{1,2}[S])?/', $data, $duration);
+ $items['year'] = isset($duration[1]) ? str_replace('Y', '', $duration[1]) : '';
+ $items['month'] = isset($duration[2]) ?str_replace('M', '', $duration[2]) : '';
+ $items['week'] = isset($duration[3]) ?str_replace('W', '', $duration[3]) : '';
+ $items['day'] = isset($duration[4]) ?str_replace('D', '', $duration[4]) : '';
+ $items['hour'] = isset($duration[6]) ?str_replace('H', '', $duration[6]) : '';
+ $items['minute'] = isset($duration[7]) ?str_replace('M', '', $duration[7]) : '';
+ $items['second'] = isset($duration[8]) ?str_replace('S', '', $duration[8]) : '';
+ $start_date = array_key_exists('DTSTART', $subgroup) ? $subgroup['DTSTART']['datetime'] : date_format(date_now(), DATE_FORMAT_ISO);
+ $timezone = array_key_exists('DTSTART', $subgroup) ? $subgroup['DTSTART']['tz'] : variable_get('date_default_timezone_name', NULL);
+ if (empty($timezone)) {
+ $timezone = 'UTC';
+ }
+ $date = date_make_date($start_date, $timezone);
+ $date2 = drupal_clone($date);
+ foreach ($items as $item => $count) {
+ if ($count > 0) {
+ date_modify($date2, '+' . $count . ' ' . $item);
+ }
+ }
+ $format = isset($subgroup['DTSTART']['type']) && $subgroup['DTSTART']['type'] == 'DATE' ? 'Y-m-d' : 'Y-m-d H:i:s';
+ $subgroup['DTEND'] = array(
+ 'datetime' => date_format($date2, DATE_FORMAT_DATETIME),
+ 'all_day' => isset($subgroup['DTSTART']['all_day']) ? $subgroup['DTSTART']['all_day'] : 0,
+ 'tz' => $timezone,
+ );
+ $duration = date_format($date2, 'U') - date_format($date, 'U');
+ $subgroup['DURATION'] = array('DATA' => $data, 'DURATION' => $duration);
+}
+
+/**
+ * Parse and clean up ical text elements.
+ */
+function date_ical_parse_text($field, $data) {
+ if (strstr($field, 'QUOTED-PRINTABLE')) {
+ $data = quoted_printable_decode($data);
+ }
+ // Strip line breaks within element.
+ $data = str_replace(array("\r\n ", "\n ", "\r "), '', $data);
+ // Put in line breaks where encoded.
+ $data = str_replace(array("\\n", "\\N"), "\n", $data);
+ // Remove other escaping.
+ $data = stripslashes($data);
+ return $data;
+}
+
+/**
+ * Parse location elements.
+ *
+ * Catch situations like the upcoming.org feed that uses
+ * LOCATION;VENUE-UID="http://upcoming.yahoo.com/venue/104/":111 First Street...
+ * or more normal LOCATION;UID=123:111 First Street...
+ * Upcoming feed would have been improperly broken on the ':' in http://
+ * so we paste the $field and $data back together first.
+ *
+ * Use non-greedy check for ':' in case there are more of them in the address.
+ */
+function date_ical_parse_location($field, $data) {
+ if (preg_match('/UID=[?"](.+)[?"][*?:](.+)/', $field . ':' . $data, $matches)) {
+ $location = array();
+ $location['UID'] = $matches[1];
+ $location['DESCRIPTION'] = stripslashes($matches[2]);
+ return $location;
+ }
+ else {
+ // Remove other escaping.
+ $location = stripslashes($data);
+ return $location;
+ }
+}
+
+/**
+ * Return a date object for the ical date, adjusted to its local timezone.
+ *
+ * @param array $ical_date
+ * An array of ical date information created in the ical import.
+ * @param string $to_tz
+ * The timezone to convert the date's value to.
+ *
+ * @return object
+ * A timezone-adjusted date object.
+ */
+function date_ical_date($ical_date, $to_tz = FALSE) {
+
+ // If the ical date has no timezone, must assume it is stateless
+ // so treat it as a local date.
+ if (empty($ical_date['datetime'])) {
+ return NULL;
+ }
+ elseif (empty($ical_date['tz'])) {
+ $from_tz = date_default_timezone_name();
+ }
+ else {
+ $from_tz = $ical_date['tz'];
+ }
+ if (strlen($ical_date['datetime']) < 11) {
+ $ical_date['datetime'] .= ' 00:00:00';
+ }
+ $date = date_make_date($ical_date['datetime'], $from_tz);
+
+ if ($to_tz && $ical_date['tz'] != '' && $to_tz != $ical_date['tz']) {
+ date_timezone_set($date, timezone_open($to_tz));
+ }
+ return $date;
+}
+
+/**
+ * Escape #text elements for safe iCal use.
+ *
+ * @param string $text
+ * Text to escape
+ *
+ * @return string
+ * Escaped text
+ *
+ */
+function date_ical_escape_text($text) {
+ $text = drupal_html_to_text($text);
+ $text = trim($text);
+ // TODO Per #38130 the iCal specs don't want : and " escaped
+ // but there was some reason for adding this in. Need to watch
+ // this and see if anything breaks.
+ // $text = str_replace('"', '\"', $text);
+ // $text = str_replace(":", "\:", $text);
+ $text = preg_replace("/\\\b/", "\\\\", $text);
+ $text = str_replace(",", "\,", $text);
+ $text = str_replace(";", "\;", $text);
+ $text = str_replace("\n", "\\n\r\n ", $text);
+ return trim($text);
+}
+
+/**
+ * Build an iCal RULE from $form_values.
+ *
+ * @param array $form_values
+ * An array constructed like the one created by date_ical_parse_rrule().
+ * [RRULE] => Array (
+ * [FREQ] => Array (
+ * [0] => MONTHLY
+ * )
+ * [BYDAY] => Array (
+ * [0] => 1SU
+ * [1] => -1SU
+ * )
+ * [UNTIL] => Array (
+ * [datetime] => 1997-21-31 09:00:00
+ * [all_day] => 0
+ * [tz] => US/Eastern
+ * )
+ * )
+ * [EXDATE] => Array (
+ * [0] = Array (
+ * [datetime] => 1997-09-21 09:00:00
+ * [all_day] => 0
+ * [tz] => US/Eastern
+ * )
+ * [1] = Array (
+ * [datetime] => 1997-10-05 09:00:00
+ * [all_day] => 0
+ * [tz] => US/Eastern
+ * )
+ * )
+ * [RDATE] => Array (
+ * [0] = Array (
+ * [datetime] => 1997-09-21 09:00:00
+ * [all_day] => 0
+ * [tz] => US/Eastern
+ * )
+ * [1] = Array (
+ * [datetime] => 1997-10-05 09:00:00
+ * [all_day] => 0
+ * [tz] => US/Eastern
+ * )
+ * )
+ */
+function date_api_ical_build_rrule($form_values) {
+ $RRULE = '';
+ if (empty($form_values) || !is_array($form_values)) {
+ return $RRULE;
+ }
+
+ // Grab the RRULE data and put them into iCal RRULE format.
+ $RRULE .= 'RRULE:FREQ=' . (!array_key_exists('FREQ', $form_values) ? 'DAILY' : $form_values['FREQ']);
+ $RRULE .= ';INTERVAL=' . (!array_key_exists('INTERVAL', $form_values) ? 1 : $form_values['INTERVAL']);
+
+ // Unset the empty 'All' values.
+ if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY'])) {
+ unset($form_values['BYDAY']['']);
+ }
+ if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH'])) {
+ unset($form_values['BYMONTH']['']);
+ }
+ if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY'])) {
+ unset($form_values['BYMONTHDAY']['']);
+ }
+
+ if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY']) && $BYDAY = implode(",", $form_values['BYDAY'])) {
+ $RRULE .= ';BYDAY=' . $BYDAY;
+ }
+ if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH']) && $BYMONTH = implode(",", $form_values['BYMONTH'])) {
+ $RRULE .= ';BYMONTH=' . $BYMONTH;
+ }
+ if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY']) && $BYMONTHDAY = implode(",", $form_values['BYMONTHDAY'])) {
+ $RRULE .= ';BYMONTHDAY=' . $BYMONTHDAY;
+ }
+ // The UNTIL date is supposed to always be expressed in UTC.
+ // The input date values may already have been converted to a date object on a
+ // previous pass, so check for that.
+ if (array_key_exists('UNTIL', $form_values) && array_key_exists('datetime', $form_values['UNTIL']) && !empty($form_values['UNTIL']['datetime'])) {
+ // We only collect a date for UNTIL, but we need it to be inclusive, so
+ // force it to a full datetime element at the last second of the day.
+ if (!is_object($form_values['UNTIL']['datetime'])) {
+ if (strlen($form_values['UNTIL']['datetime']) < 11) {
+ $form_values['UNTIL']['datetime'] .= ' 23:59:59';
+ $form_values['UNTIL']['granularity'] = serialize(drupal_map_assoc(array('year', 'month', 'day', 'hour', 'minute', 'second')));
+ $form_values['UNTIL']['all_day'] = FALSE;
+ }
+ $until = date_ical_date($form_values['UNTIL'], 'UTC');
+ }
+ else {
+ $until = $form_values['UNTIL']['datetime'];
+ }
+ $RRULE .= ';UNTIL=' . date_format($until, DATE_FORMAT_ICAL) . 'Z';
+ }
+ // Our form doesn't allow a value for COUNT, but it may be needed by
+ // modules using the API, so add it to the rule.
+ if (array_key_exists('COUNT', $form_values)) {
+ $RRULE .= ';COUNT=' . $form_values['COUNT'];
+ }
+
+ // iCal rules presume the week starts on Monday unless otherwise specified,
+ // so we'll specify it.
+ if (array_key_exists('WKST', $form_values)) {
+ $RRULE .= ';WKST=' . $form_values['WKST'];
+ }
+ else {
+ $RRULE .= ';WKST=' . date_repeat_dow2day(variable_get('date_first_day', 0));
+ }
+
+ // Exceptions dates go last, on their own line.
+ // The input date values may already have been converted to a date
+ // object on a previous pass, so check for that.
+ if (isset($form_values['EXDATE']) && is_array($form_values['EXDATE'])) {
+ $ex_dates = array();
+ foreach ($form_values['EXDATE'] as $value) {
+ if (!empty($value['datetime'])) {
+ $date = !is_object($value['datetime']) ? date_ical_date($value, 'UTC') : $value['datetime'];
+ $ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z': '';
+ if (!empty($ex_date)) {
+ $ex_dates[] = $ex_date;
+ }
+ }
+ }
+ if (!empty($ex_dates)) {
+ sort($ex_dates);
+ $RRULE .= chr(13) . chr(10) . 'EXDATE:' . implode(',', $ex_dates);
+ }
+ }
+ elseif (!empty($form_values['EXDATE'])) {
+ $RRULE .= chr(13) . chr(10) . 'EXDATE:' . $form_values['EXDATE'];
+ }
+
+ // Exceptions dates go last, on their own line.
+ if (isset($form_values['RDATE']) && is_array($form_values['RDATE'])) {
+ $ex_dates = array();
+ foreach ($form_values['RDATE'] as $value) {
+ $date = !is_object($value['datetime']) ? date_ical_date($value, 'UTC') : $value['datetime'];
+ $ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z': '';
+ if (!empty($ex_date)) {
+ $ex_dates[] = $ex_date;
+ }
+ }
+ if (!empty($ex_dates)) {
+ sort($ex_dates);
+ $RRULE .= chr(13) . chr(10) . 'RDATE:' . implode(',', $ex_dates);
+ }
+ }
+ elseif (!empty($form_values['RDATE'])) {
+ $RRULE .= chr(13) . chr(10) . 'RDATE:' . $form_values['RDATE'];
+ }
+
+ return $RRULE;
+}
diff --git a/sites/all/modules/date/date_api_sql.inc b/sites/all/modules/date/date_api_sql.inc
new file mode 100644
index 0000000..9b8f73e
--- /dev/null
+++ b/sites/all/modules/date/date_api_sql.inc
@@ -0,0 +1,881 @@
+db_type = $GLOBALS['db_type'];
+ $this->date_type = $date_type;
+ $this->db_timezone = 'UTC';
+ $this->local_timezone = isset($local_timezone) ? $local_timezone : date_default_timezone_name();
+ if (isset($this->definition['content_field'])) {
+ $this->date_handler->date_type = $this->definition['content_field']['type'];
+ }
+ date_api_set_db_timezone();
+ }
+
+ /**
+ * See if the db has timezone name support.
+ */
+ function db_tz_support($reset = FALSE) {
+ $has_support = variable_get('date_db_tz_support', -1);
+ if ($has_support == -1 || $reset) {
+ date_api_set_db_timezone();
+ $has_support = FALSE;
+ switch ($this->db_type) {
+ case 'mysql':
+ case 'mysqli':
+ if (version_compare(db_version(), '4.1.3', '>=')) {
+ $test = db_result(db_query("SELECT CONVERT_TZ('2008-02-15 12:00:00', 'UTC', 'US/Central')"));
+ if ($test == '2008-02-15 06:00:00') {
+ $has_support = TRUE;
+ }
+ }
+ break;
+ case 'pgsql':
+ $test = db_result(db_query("SELECT '2008-02-15 12:00:00 UTC' AT TIME ZONE 'US/Central'"));
+ if ($test == '2008-02-15 06:00:00') {
+ $has_support = TRUE;
+ }
+ break;
+ }
+ variable_set('date_db_tz_support', $has_support);
+ }
+ return $has_support;
+ }
+
+ /**
+ * Set the database timzone offset.
+ *
+ * Setting the db timezone to UTC is done to ensure consistency in date
+ * handling whether or not the database can do proper timezone conversion.
+ *
+ * Views filters that not exposed are cached and won't set the timezone
+ * so views date filters should add 'cacheable' => 'no' to their
+ * definitions to ensure that the database timezone gets set properly
+ * when the query is executed.
+ *
+ * @param $offset
+ * An offset value to set the database timezone to. This will only
+ * set a fixed offset, not a timezone, so any value other than
+ * '+00:00' should be used with caution.
+ */
+ function set_db_timezone($offset = '+00:00') {
+ static $already_set = FALSE;
+ $type = $GLOBALS['db_type'];
+ if (!$already_set) {
+ if (($type == 'mysqli' || $type == 'mysql') && version_compare(db_version(), '4.1.3', '>=')) {
+ db_query("SET @@session.time_zone = '$offset'");
+ }
+ elseif ($type == 'pgsql') {
+ db_query("SET TIME ZONE INTERVAL '$offset' HOUR TO MINUTE");
+ }
+ $already_set = TRUE;
+ }
+ }
+
+ /**
+ * Return timezone offset for the date being processed.
+ */
+ function get_offset() {
+ if (!empty($this->db_timezone) && !empty($this->local_timezone)) {
+ if ($this->db_timezone != $this->local_timezone) {
+ $date = date_now($this->db_timezone);
+ date_timezone_set($date, timezone_open($this->local_timezone));
+ return date_offset_get($date);
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Helper function to create cross-database SQL dates.
+ *
+ * @param $field
+ * The real table and field name, like 'tablename.fieldname'.
+ * @param $offset
+ * The name of a field that holds the timezone offset or an
+ * offset value. If NULL, the normal Drupal timezone handling
+ * will be used, if $offset = 0 no adjustment will be made.
+ * @return
+ * An appropriate SQL string for the db type and field type.
+ */
+ function sql_field($field, $offset = NULL) {
+ if (drupal_strtoupper($field) == 'NOW') {
+ // NOW() will be in UTC since that is what we set the db timezone to.
+ $this->local_timezone = 'UTC';
+ return $this->sql_offset('NOW()', $offset);
+ }
+ switch ($this->db_type) {
+ case 'mysql':
+ case 'mysqli':
+ switch ($this->date_type) {
+ case DATE_UNIX:
+ $field = "FROM_UNIXTIME($field)";
+ break;
+ case DATE_ISO:
+ if (version_compare(db_version(), '4.1.1', '>=')) {
+ $field = "STR_TO_DATE($field, '%Y-%m-%%dT%T')";
+ }
+ else {
+ $field = "REPLACE($field, 'T', ' ')";
+ }
+ break;
+ case DATE_DATETIME:
+ break;
+ }
+ break;
+ case 'pgsql':
+ switch ($this->date_type) {
+ case DATE_UNIX:
+ $field = "$field::ABSTIME";
+ break;
+ case DATE_ISO:
+ $field = "TO_DATE($field, 'FMYYYY-FMMM-FMDDTFMHH24:FMMI:FMSS')";
+ break;
+ case DATE_DATETIME:
+ break;
+ }
+ break;
+ }
+ // Adjust the resulting value to the right timezone/offset.
+ return $this->sql_tz($field, $offset);
+ }
+
+ /**
+ * Adjust a field value by an offset in seconds.
+ */
+ function sql_offset($field, $offset = NULL) {
+ if (!empty($offset)) {
+ switch ($this->db_type) {
+ case 'mysql':
+ case 'mysqli':
+ if (version_compare(db_version(), '4.1.1', '>=')) {
+ return "ADDTIME($field, SEC_TO_TIME($offset))";
+ }
+ else {
+ return "DATE_ADD(CAST($field AS DATETIME), INTERVAL $offset SECOND)";
+ }
+ case 'pgsql':
+ return "($field + INTERVAL '$offset SECONDS')";;
+ }
+ }
+ return $field;
+ }
+
+ /**
+ * Adjust a field value by time interval.
+ *
+ * @param $field
+ * The field to be adjusted.
+ * @param $direction
+ * Either ADD or SUB.
+ * @param $count
+ * The number of values to adjust.
+ * @param $granularity
+ * The granularity of the adjustment, should be singular,
+ * like SECOND, MINUTE, DAY, HOUR.
+ */
+ function sql_date_math($field, $direction, $count, $granularity) {
+ $granularity = drupal_strtoupper($granularity);
+ switch ($this->db_type) {
+ case 'mysql':
+ case 'mysqli':
+ switch ($direction) {
+ case 'ADD':
+ return "DATE_ADD(CAST($field AS DATETIME), INTERVAL $count $granularity)";
+ case 'SUB':
+ return "DATE_SUB(CAST($field AS DATETIME), INTERVAL $count $granularity)";
+ }
+
+ case 'pgsql':
+ $granularity .= 'S';
+ switch ($direction) {
+ case 'ADD':
+ return "($field + INTERVAL '$count $granularity')";
+ case 'SUB':
+ return "($field - INTERVAL '$count $granularity')";
+ }
+ }
+ return $field;
+ }
+
+ /**
+ * Select a date value from the database, adjusting the value
+ * for the timezone.
+ *
+ * Check whether database timezone conversion is supported in
+ * this system and use it if possible, otherwise use an
+ * offset.
+ *
+ * @param $offset
+ * Set a fixed offset or offset field to use for the date.
+ * If set, no timezone conversion will be done and the
+ * offset will be used.
+ */
+ function sql_tz($field, $offset = NULL) {
+ // If the timezones are values they need to be quoted, but
+ // if they are field names they do not.
+ $db_zone = $this->db_timezone_field ? $this->db_timezone_field : "'{$this->db_timezone}'";
+ $localzone = $this->local_timezone_field ? $this->local_timezone_field : "'{$this->local_timezone}'";
+
+ // If a fixed offset is required, use it.
+ if ($offset !== NULL) {
+ return $this->sql_offset($field, $offset);
+ }
+ // If the db and local timezones are the same, make no adjustment.
+ elseif ($db_zone == $localzone) {
+ return $this->sql_offset($field, 0);
+ }
+ // If the db has no timezone support, adjust by the offset,
+ // could be either a field name or a value.
+ elseif (!$this->db_tz_support()) {
+ if (!empty($this->offset_field)) {
+ return $this->sql_offset($field, $this->offset_field);
+ }
+ else {
+ return $this->sql_offset($field, $this->get_offset());
+ }
+ }
+ // Otherwise make a database timezone adjustment to the field.
+ else {
+ switch ($this->db_type) {
+ case 'mysql':
+ case 'mysqli':
+ return "CONVERT_TZ($field, $db_zone, $localzone)";
+ case 'pgsql':
+ // WITH TIME ZONE assumes the date is using the system
+ // timezone, which should have been set to UTC.
+ return "$field::timestamp with time zone AT TIME ZONE $localzone";
+ }
+ }
+ }
+
+ /**
+ * Helper function to create cross-database SQL date formatting.
+ *
+ * @param $format
+ * A format string for the result, like 'Y-m-d H:i:s'.
+ * @param $field
+ * The real table and field name, like 'tablename.fieldname'.
+ * @return
+ * An appropriate SQL string for the db type and field type.
+ */
+ function sql_format($format, $field) {
+ switch ($this->db_type) {
+ case 'mysql':
+ case 'mysqli':
+ $replace = array(
+ 'Y' => '%Y', 'y' => '%y',
+ 'm' => '%m', 'n' => '%c',
+ 'd' => '%%d', 'j' => '%e',
+ 'H' => '%H',
+ 'i' => '%i',
+ 's' => '%%s',
+ '\WW' => 'W%U',
+ );
+ $format = strtr($format, $replace);
+ return "DATE_FORMAT($field, '$format')";
+ case 'pgsql':
+ $replace = array(
+ 'Y' => 'YYYY', 'y' => 'Y',
+ 'm' => 'MM', 'n' => 'M',
+ 'd' => 'DD', 'j' => 'D',
+ 'H' => 'HH24',
+ 'i' => 'MI',
+ 's' => 'SS',
+ '\T' => '"T"',
+ //'\W' => // TODO, what should this be?
+ );
+ $format = strtr($format, $replace);
+ return "TO_CHAR($field, '$format')";
+ }
+ }
+
+ /**
+ * Helper function to create cross-database SQL date extraction.
+ *
+ * @param $extract_type
+ * The type of value to extract from the date, like 'MONTH'.
+ * @param $field
+ * The real table and field name, like 'tablename.fieldname'.
+ * @return
+ * An appropriate SQL string for the db type and field type.
+ */
+ function sql_extract($extract_type, $field) {
+ // Note there is no space after FROM to avoid db_rewrite problems
+ // see http://drupal.org/node/79904.
+ switch (drupal_strtoupper($extract_type)) {
+ case ('DATE'):
+ return $field;
+ case ('YEAR'):
+ return "EXTRACT(YEAR FROM($field))";
+ case ('MONTH'):
+ return "EXTRACT(MONTH FROM($field))";
+ case ('DAY'):
+ return "EXTRACT(DAY FROM($field))";
+ case ('HOUR'):
+ return "EXTRACT(HOUR FROM($field))";
+ case ('MINUTE'):
+ return "EXTRACT(MINUTE FROM($field))";
+ case ('SECOND'):
+ return "EXTRACT(SECOND FROM($field))";
+ case ('WEEK'): // ISO week number for date
+ switch ($this->db_type) {
+ case ('mysql'):
+ case ('mysqli'):
+ // WEEK using arg 3 in mysql should return the same value as postgres EXTRACT
+ return "WEEK($field, 3)";
+ case ('pgsql'):
+ return "EXTRACT(WEEK FROM($field))";
+ }
+ case ('DOW'):
+ switch ($this->db_type) {
+ case ('mysql'):
+ case ('mysqli'):
+ // mysql returns 1 for Sunday through 7 for Saturday
+ // php date functions and postgres use 0 for Sunday and 6 for Saturday
+ return "INTEGER(DAYOFWEEK($field) - 1)";
+ case ('pgsql'):
+ return "EXTRACT(DOW FROM($field))";
+ }
+ case ('DOY'):
+ switch ($this->db_type) {
+ case ('mysql'):
+ case ('mysqli'):
+ return "DAYOFYEAR($field)";
+ case ('pgsql'):
+ return "EXTRACT(DOY FROM($field))";
+ }
+ }
+ }
+
+ /**
+ * Create a where clause to compare a complete date field to a complete date value.
+ *
+ * @param string $type
+ * The type of value we're comparing to, could be another field
+ * or a date value.
+ * @param string $field
+ * The db table and field name, like "$table.$field".
+ * @param string $operator
+ * The db comparison operator to use, like '='.
+ * @param int $value
+ * The value to compare the extracted date part to, could be a
+ * field name or a date string or NOW().
+ * @return
+ * SQL for the where clause for this operation.
+ */
+ function sql_where_date($type, $field, $operator, $value, $adjustment = NULL) {
+ $type = drupal_strtoupper($type);
+ if (drupal_strtoupper($value) == 'NOW') {
+ $value = $this->sql_field('NOW', $adjustment);
+ }
+ elseif ($type == 'FIELD') {
+ $value = $this->sql_field($value, $adjustment);
+ }
+ elseif ($type == 'DATE') {
+ $date = date_make_date($value, date_default_timezone_name(), DATE_DATETIME);
+ if (!empty($adjustment)) {
+ date_modify($date, $adjustment .' seconds');
+ }
+ // When comparing a field to a date we can avoid doing timezone
+ // conversion by altering the comparison date to the db timezone.
+ // This won't work if the timezone is a field instead of a value.
+ if (empty($this->db_timezone_field) && empty($this->local_timezone_field) && $this->db_timezone_field != $this->local_timezone_field) {
+ date_timezone_set($date, timezone_open($this->db_timezone));
+ $this->local_timezone = $this->db_timezone;
+ }
+ $value = "'". date_format_date($date, 'custom', DATE_FORMAT_DATETIME) ."'";
+ }
+ if ($this->local_timezone != $this->db_timezone) {
+ $field = $this->sql_field($field);
+ }
+ else {
+ $field = $this->sql_field($field, 0);
+ }
+ return "$field $operator $value";
+ }
+
+ /**
+ * Create a where clause to compare an extracted part of a field to an integer value.
+ *
+ * @param string $part
+ * The part to extract, YEAR, MONTH, DAY, etc.
+ * @param string $field
+ * The db table and field name, like "$table.$field".
+ * @param string $operator
+ * The db comparison operator to use, like '='.
+ * @param int $value
+ * The integer value to compare the extracted date part to.
+ * @return
+ * SQL for the where clause for this operation.
+ */
+ function sql_where_extract($part, $field, $operator, $value, $adjustment = NULL) {
+ $field = $this->sql_field($field, $adjustment);
+ return $this->sql_extract($part, $field) ." $operator $value";
+ }
+
+ /**
+ * Create a where clause to compare a formated field to a formated value.
+ *
+ * @param string $format
+ * The format to use on the date and the value when comparing them.
+ * @param string $field
+ * The db table and field name, like "$table.$field".
+ * @param string $operator
+ * The db comparison operator to use, like '='.
+ * @param string $value
+ * The value to compare the extracted date part to, could be a
+ * field name or a date string or NOW().
+ * @return
+ * SQL for the where clause for this operation.
+ */
+ function sql_where_format($format, $field, $operator, $value, $adjustment = NULL) {
+ $field = $this->sql_field($field, $adjustment);
+ return $this->sql_format($format, $field) ." $operator '$value'";
+ }
+
+ /**
+ * An array of all date parts,
+ * optionally limited to an array of allowed parts.
+ */
+ function date_parts($limit = NULL) {
+ $parts = array(
+ 'year' => date_t('Year', 'datetime'), 'month' => date_t('Month', 'datetime'), 'day' => date_t('Day', 'datetime'),
+ 'hour' => date_t('Hour', 'datetime'), 'minute' => date_t('Minute', 'datetime'), 'second' => date_t('Second', 'datetime'),
+ );
+ if (!empty($limit)) {
+ $last = FALSE;
+ foreach ($parts as $key => $part) {
+ if ($last) {
+ unset($parts[$key]);
+ }
+ if ($key == $limit) {
+ $last = TRUE;
+ }
+ }
+ }
+ return $parts;
+ }
+
+ /**
+ * Part information.
+ *
+ * @param $op
+ * 'min', 'max', 'format', 'sep', 'empty_now', 'empty_min', 'empty_max'.
+ * Returns all info if empty.
+ * @param $part
+ * 'year', 'month', 'day', 'hour', 'minute', or 'second.
+ * returns info for all parts if empty.
+ */
+ function part_info($op = NULL, $part = NULL) {
+ $info = array();
+ $info['min'] = array(
+ 'year' => 100, 'month' => 1, 'day' => 1,
+ 'hour' => 0, 'minute' => 0, 'second' => 0);
+ $info['max'] = array(
+ 'year' => 4000, 'month' => 12, 'day' => 31,
+ 'hour' => 23, 'minute' => 59, 'second' => 59);
+ $info['format'] = array(
+ 'year' => 'Y', 'month' => 'm', 'day' => 'd',
+ 'hour' => 'H', 'minute' => 'i', 'second' => 's');
+ $info['sep'] = array(
+ 'year' => '', 'month' => '-', 'day' => '-',
+ 'hour' => ' ', 'minute' => ':', 'second' => ':');
+ $info['empty_now'] = array(
+ 'year' => date('Y'), 'month' => date('m'), 'day' => min('28', date('d')),
+ 'hour' => date('H'), 'minute' => date('i'), 'second' => date('s'));
+ $info['empty_min'] = array(
+ 'year' => '1000', 'month' => '01', 'day' => '01',
+ 'hour' => '00', 'minute' => '00', 'second' => '00');
+ $info['empty_max'] = array(
+ 'year' => '9999', 'month' => '12', 'day' => '31',
+ 'hour' => '23', 'minute' => '59', 'second' => '59');
+ if (!empty($op)) {
+ if (!empty($part)) {
+ return $info[$op][$part];
+ }
+ else {
+ return $info[$op];
+ }
+ }
+ return $info;
+ }
+
+ /**
+ * Create a complete datetime value out of an
+ * incomplete array of selected values.
+ *
+ * For example, array('year' => 2008, 'month' => 05) will fill
+ * in the day, hour, minute and second with the earliest possible
+ * values if type = 'min', the latest possible values if type = 'max',
+ * and the current values if type = 'now'.
+ */
+ function complete_date($selected, $type = 'now') {
+ if (empty($selected)) {
+ return '';
+ }
+ // Special case for weeks.
+ if (array_key_exists('week', $selected)) {
+ $dates = date_week_range($selected['week'], $selected['year']);
+ switch ($type) {
+ case 'empty_now':
+ case 'empty_min':
+ case 'min':
+ return date_format($dates[0], 'Y-m-d H:i:s');
+ case 'empty_max':
+ case 'max':
+ return date_format($dates[1], 'Y-m-d H:i:s');
+ default:
+ return;
+ }
+ }
+
+ $compare = array_merge($this->part_info('empty_'. $type), $selected);
+ // If this is a max date, make sure the last day of
+ // the month is the right one for this date.
+ if ($type == 'max') {
+ $compare['day'] = date_days_in_month($compare['year'], $compare['month']);
+ }
+ $value = '';
+ $separators = $this->part_info('sep');
+ foreach ($this->date_parts() as $key => $name) {
+ $value .= $separators[$key] . (!empty($selected[$key]) ? $selected[$key] : $compare[$key]);
+ }
+ return $value;
+ }
+ /**
+ * Convert a format string into help text,
+ * i.e. 'Y-m-d' becomes 'YYYY-MM-DD'.
+ *
+ * @param unknown_type $format
+ * @return unknown
+ */
+ function format_help($format) {
+ $replace = array(
+ 'Y' => 'YYYY', 'm' => 'MM', 'd' => 'DD',
+ 'H' => 'HH', 'i' => 'MM', 's' => 'SS', '\T' => 'T');
+ return strtr($format, $replace);
+ }
+
+ /**
+ * A function to test the validity of various date parts
+ */
+ function part_is_valid($value, $type) {
+ if ( !preg_match('/^[0-9]*$/', $value) ) {
+ return FALSE;
+ }
+ $value = intval($value);
+ if ($value <= 0) return FALSE;
+ switch ($type) {
+ case 'year':
+ if ($value < DATE_MIN_YEAR) return FALSE;
+ break;
+ case 'month':
+ if ($value < 0 || $value > 12) return FALSE;
+ break;
+ case 'day':
+ if ($value < 0 || $value > 31) return FALSE;
+ break;
+ case 'week':
+ if ($value < 0 || $value > 53) return FALSE;
+ }
+ return TRUE;
+ }
+
+ function views_formats($granularity, $type = 'sql') {
+ $formats = array('display', 'sql');
+ // Start with the site long date format and add seconds to it
+ $long = str_replace(':i', ':i:s', variable_get('date_format_long', 'l, F j, Y - H:i'));
+ switch ($granularity) {
+ case ('year'):
+ $formats['display'] = 'Y';
+ $formats['sql'] = 'Y';
+ break;
+ case ('month'):
+ $formats['display'] = date_limit_format($long, array('year', 'month'));
+ $formats['sql'] = 'Y-m';
+ break;
+ case ('day'):
+ $formats['display'] = date_limit_format($long, array('year', 'month', 'day'));
+ $formats['sql'] = 'Y-m-d';
+ break;
+ case ('hour'):
+ $formats['display'] = date_limit_format($long, array('year', 'month', 'day', 'hour'));
+ $formats['sql'] = 'Y-m-d\TH';
+ break;
+ case ('minute'):
+ $formats['display'] = date_limit_format($long, array('year', 'month', 'day', 'hour', 'minute'));
+ $formats['sql'] = 'Y-m-d\TH:i';
+ break;
+ case ('second'):
+ $formats['display'] = date_limit_format($long, array('year', 'month', 'day', 'hour', 'minute', 'second'));
+ $formats['sql'] = 'Y-m-d\TH:i:s';
+ break;
+ case ('week'):
+ $formats['display'] = 'F j Y (W)';
+ $formats['sql'] = 'Y-\WW';
+ break;
+ }
+ return $formats[$type];
+ }
+
+ function granularity_form($granularity) {
+ $form = array(
+ '#title' => t('Granularity'),
+ '#type' => 'radios',
+ '#default_value' => $granularity,
+ '#options' => $this->date_parts(),
+ );
+ return $form;
+ }
+
+ /**
+ * Parse date parts from an ISO date argument.
+ *
+ * Based on ISO 8601 date duration and time interval standards.
+ *
+ * See http://en.wikipedia.org/wiki/ISO_8601#Week_dates for definitions of ISO weeks.
+ * See http://en.wikipedia.org/wiki/ISO_8601#Duration for definitions of ISO duration and time interval.
+ *
+ * Parses a value like 2006-01-01--2006-01-15, or 2006-W24, or @P1W.
+ * Separate from and to dates or date and period with a double hyphen (--).
+ *
+ * The 'to' portion of the argument can be eliminated if it is the same as the 'from' portion.
+ * Use @ instead of a date to substitute in the current date and time.
+ *
+ * Use periods (P1H, P1D, P1W, P1M, P1Y) to get next hour/day/week/month/year from now.
+ * Use date before P sign to get next hour/day/week/month/year from that date.
+ * Use period then date to get a period that ends on the date.
+ *
+ */
+ function arg_parts($argument) {
+ $values = array();
+ // Keep mal-formed arguments from creating errors.
+ if (empty($argument) || is_array($argument)) {
+ return array('date' => array(), 'period' => array());
+ }
+ $fromto = explode('--', $argument);
+ foreach ($fromto as $arg) {
+ $parts = array();
+ if ($arg == '@') {
+ $parts['date'] = date_array(date_now());
+ }
+ elseif (preg_match('/(\d{4})?-?(W)?(\d{1,2})?-?(\d{1,2})?[T\s]?(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?/', $arg, $matches)) {
+ $date = array();
+ if (!empty($matches[1])) $date['year'] = $matches[1];
+ if (!empty($matches[3])) {
+ if (empty($matches[2])) {
+ $date['month'] = $matches[3];
+ }
+ else {
+ $date['week'] = $matches[3];
+ }
+ }
+ if (!empty($matches[4])) $date['day'] = $matches[4];
+ if (!empty($matches[5])) $date['hour'] = $matches[5];
+ if (!empty($matches[6])) $date['minute'] = $matches[6];
+ if (!empty($matches[7])) $date['second'] = $matches[7];
+ $parts['date'] = $date;
+ }
+ if (preg_match('/^P(\d{1,4}[Y])?(\d{1,2}[M])?(\d{1,2}[W])?(\d{1,2}[D])?([T]{0,1})?(\d{1,2}[H])?(\d{1,2}[M])?(\d{1,2}[S])?/', $arg, $matches)) {
+ $period = array();
+ if (!empty($matches[1])) $period['year'] = str_replace('Y', '', $matches[1]);
+ if (!empty($matches[2])) $period['month'] = str_replace('M', '', $matches[2]);
+ if (!empty($matches[3])) $period['week'] = str_replace('W', '', $matches[3]);
+ if (!empty($matches[4])) $period['day'] = str_replace('D', '', $matches[4]);
+ if (!empty($matches[6])) $period['hour'] = str_replace('H', '', $matches[6]);
+ if (!empty($matches[7])) $period['minute'] = str_replace('M', '', $matches[7]);
+ if (!empty($matches[8])) $period['second'] = str_replace('S', '', $matches[8]);
+ $parts['period'] = $period;
+ }
+ $values[] = $parts;
+ }
+ return $values;
+ }
+
+ /**
+ * Convert strings like '+1 day' to the ISO equivalent, like 'P1D'.
+ */
+ function arg_replace($arg) {
+ if (!preg_match('/([+|-])\s?([0-9]{1,32})\s?([day(s)?|week(s)?|month(s)?|year(s)?|hour(s)?|minute(s)?|second(s)?]{1,10})/', $arg, $results)) {
+ return str_replace('now', '@', $arg);
+ }
+ $direction = $results[1];
+ $count = $results[2];
+ $item = $results[3];
+
+ $replace = array(
+ 'now' => '@',
+ '+' => 'P',
+ '-' => 'P-',
+ 'years' => 'Y',
+ 'year' => 'Y',
+ 'months' => 'M',
+ 'month' => 'M',
+ 'weeks' => 'W',
+ 'week' => 'W',
+ 'days' => 'D',
+ 'day' => 'D',
+ 'hours' => 'H',
+ 'hour' => 'H',
+ 'minutes' => 'M',
+ 'minute' => 'M',
+ 'seconds' => 'S',
+ 'second' => 'S',
+ ' ' => '',
+ ' ' => '',
+ );
+ $prefix = in_array($item, array('hours', 'hour', 'minutes', 'minute', 'seconds', 'second')) ? 'T' : '';
+ return $prefix . strtr($direction, $replace) . $count . strtr($item, $replace);
+ }
+
+ /**
+ * Use the parsed values from the ISO argument to determine the
+ * granularity of this period.
+ */
+ function arg_granularity($arg) {
+ $granularity = '';
+ $parts = $this->arg_parts($arg);
+ $date = !empty($parts[0]['date']) ? $parts[0]['date'] : (!empty($parts[1]['date']) ? $parts[1]['date'] : array());
+ foreach ($date as $key => $part) {
+ $granularity = $key;
+ }
+ return $granularity;
+ }
+
+ /**
+ * Use the parsed values from the ISO argument to determine the
+ * min and max date for this period.
+ */
+ function arg_range($arg) {
+ // Parse the argument to get its parts
+ $parts = $this->arg_parts($arg);
+
+ // Build a range from a period-only argument (assumes the min date is now.)
+ if (empty($parts[0]['date']) && !empty($parts[0]['period']) && (empty($parts[1]))) {
+ $min_date = date_now();
+ $max_date = drupal_clone($min_date);
+ foreach ($parts[0]['period'] as $part => $value) {
+ date_modify($max_date, "+$value $part");
+ }
+ date_modify($max_date, '-1 second');
+ return array($min_date, $max_date);
+ }
+ // Build a range from a period to period argument
+ if (empty($parts[0]['date']) && !empty($parts[0]['period']) && !empty($parts[1]['period'])) {
+ $min_date = date_now();
+ $max_date = drupal_clone($min_date);
+ foreach ($parts[0]['period'] as $part => $value) {
+ date_modify($min_date, "+$value $part");
+ }
+ date_modify($min_date, '-1 second');
+ foreach ($parts[1]['period'] as $part => $value) {
+ date_modify($max_date, "+$value $part");
+ }
+ date_modify($max_date, '-1 second');
+ return array($min_date, $max_date);
+ }
+ if (!empty($parts[0]['date'])) {
+ $value = date_fuzzy_datetime($this->complete_date($parts[0]['date'], 'min'));
+ $min_date = date_make_date($value, date_default_timezone_name(), DATE_ISO);
+ // Build a range from a single date-only argument.
+ if (empty($parts[1]) || (empty($parts[1]['date']) && empty($parts[1]['period']))) {
+ $value = date_fuzzy_datetime($this->complete_date($parts[0]['date'], 'max'));
+ $max_date = date_make_date($value, date_default_timezone_name(), DATE_ISO);
+ return array($min_date, $max_date);
+ }
+ // Build a range from start date + period.
+ elseif (!empty($parts[1]['period'])) {
+ foreach ($parts[1]['period'] as $part => $value) {
+ $max_date = drupal_clone($min_date);
+ date_modify($max_date, "+$value $part");
+ }
+ date_modify($max_date, '-1 second');
+ return array($min_date, $max_date);
+ }
+ }
+ // Build a range from start date and end date.
+ if (!empty($parts[1]['date'])) {
+ $value = date_fuzzy_datetime($this->complete_date($parts[1]['date'], 'max'));
+ $max_date = date_make_date($value, date_default_timezone_name(), DATE_ISO);
+ if (isset($min_date)) {
+ return array($min_date, $max_date);
+ }
+ }
+ // Build a range from period + end date.
+ if (!empty($parts[0]['period'])) {
+ $min_date = date_now();
+ foreach ($parts[0]['period'] as $part => $value) {
+ date_modify($min_date, "$value $part");
+ }
+ return array($min_date, $max_date);
+ }
+ // Intercept invalid info and fall back to the current date.
+ $now = date_now();
+ return array($now, $now);
+ }
+}
\ No newline at end of file
diff --git a/sites/all/modules/date/date_locale/date_locale.info b/sites/all/modules/date/date_locale/date_locale.info
new file mode 100644
index 0000000..c2cf608
--- /dev/null
+++ b/sites/all/modules/date/date_locale/date_locale.info
@@ -0,0 +1,13 @@
+name = Date Locale
+description = Allows the site admin to configure multiple formats for date/time display to tailor dates for a specific locale or audience.
+package = Date/Time
+dependencies[] = date_api
+dependencies[] = locale
+core = 6.x
+
+; Information added by Drupal.org packaging script on 2014-03-31
+version = "6.x-2.10"
+core = "6.x"
+project = "date"
+datestamp = "1396284252"
+
diff --git a/sites/all/modules/date/date_locale/date_locale.module b/sites/all/modules/date/date_locale/date_locale.module
new file mode 100644
index 0000000..81e1ee4
--- /dev/null
+++ b/sites/all/modules/date/date_locale/date_locale.module
@@ -0,0 +1,295 @@
+language);
+ if (module_exists('site_country')) {
+ $country_code = variable_get('site_country_default_country', '');
+ if (!empty($country_code)) {
+ $country_language = $language->language . '-' . $country_code;
+ array_unshift($languages, $country_language);
+ }
+ }
+ drupal_alter('date_format_languages', $languages);
+
+ // Setup appropriate date formats for this locale.
+ $formats = date_locale_get_locale_date_format($languages);
+ foreach ($formats as $format_type => $format) {
+ $conf[$format_type] = $format;
+ }
+ }
+}
+
+/**
+ * Implementation of hook_menu().
+ */
+function date_locale_menu() {
+ $items = array();
+ $items['admin/settings/date-time/locale'] = array(
+ 'title' => 'Locale date settings',
+ 'description' => 'Configure date formats for each locale',
+ 'type' => MENU_LOCAL_TASK,
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('date_locale_format_form'),
+ 'access arguments' => array('administer site configuration'),
+ 'weight' => 1,
+ );
+ return $items;
+}
+
+/**
+ * Select locale date format details from database.
+ *
+ * @param $languages
+ * An array of language codes.
+ * @return
+ * An array of date formats.
+ */
+function date_locale_get_locale_date_format($languages) {
+ $formats = array();
+
+ // Get list of different format types.
+ $format_types = date_get_format_types();
+ $short_default = variable_get('date_format_short', 'm/d/Y - H:i');
+
+ // Loop through each language until we find one with some date formats
+ // configured.
+ foreach ($languages as $language) {
+ $date_formats = date_format_locale($language);
+ if (!empty($date_formats)) {
+ // We have locale-specific date formats, so check for their types. If
+ // we're missing a type, use the default setting instead.
+ foreach ($format_types as $type => $type_info) {
+ if (isset($date_formats[$type])) {
+ $format = $date_formats[$type];
+
+ // If format exists for this language, use it.
+ if (!empty($format)) {
+ $formats['date_format_' . $type] = $format;
+ }
+ // Otherwise get default variable setting. If this is not set, default
+ // to the short format.
+ else {
+ $formats['date_format_' . $type] = variable_get('date_format_' . $type, $short_default);
+ }
+ }
+ }
+
+ // Return on the first match.
+ return $formats;
+ }
+ }
+
+ // No locale specific formats found, so use defaults.
+ $system_types = array('short', 'medium', 'long');
+ // Handle system types separately as they have defaults if no variable exists.
+ $formats['date_format_short'] = $short_default;
+ $formats['date_format_medium'] = variable_get('date_format_medium', 'D, m/d/Y - H:i');
+ $formats['date_format_long'] = variable_get('date_format_long', 'l, F j, Y - H:i');
+
+ // For non-system types, get the default setting, otherwise use the short
+ // format.
+ foreach ($format_types as $type => $type_info) {
+ if (!in_array($type, $system_types)) {
+ $formats['date_format_' . $type] = variable_get('date_format_' . $type, $short_default);
+ }
+ }
+
+ return $formats;
+}
+
+/**
+ * Display list of enabled languages to configure date formats for.
+ */
+function date_locale_format_form($form_state) {
+ $form = array();
+
+ if (!isset($form_state['values'])) {
+ $step = 'languages';
+ }
+ else {
+ $step = 'config';
+ }
+ $form['step'] = array(
+ '#type' => 'value',
+ '#value' => $step,
+ );
+
+ // Form part 1: show language selection.
+ if ($step == 'languages') {
+ // Get list of languages.
+ $languages = locale_language_list('native');
+
+ // If site_country module is enabled, add country specific languages to
+ // languages array.
+ if (module_exists('site_country')) {
+ $country_code = variable_get('site_country_default_country', '');
+ if (!empty($country_code)) {
+ foreach ($languages as $langcode => $name) {
+ $country_language = $langcode . '-' . $country_code;
+ if (drupal_strlen($langcode) == 2 && !in_array($country_language, array_keys($languages))) {
+ $languages[$country_language] = "$name ($country_code)";
+ }
+ }
+ }
+ }
+
+ $form['langcode'] = array(
+ '#title' => t('Language'),
+ '#type' => 'select',
+ '#options' => $languages,
+ '#multiple' => FALSE,
+ );
+
+ $form['buttons']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Search'),
+ '#submit' => array('date_locale_format_form_language_submit'),
+ );
+
+ }
+
+ // Form part 2: show date formats for this language.
+ else {
+ // Add Drupal core's system.js and js settings.
+ date_api_add_system_javascript();
+ $languages = locale_language_list('native');
+ $langcode = $form_state['values']['langcode'];
+ $language_name = $languages[$langcode];
+
+ // Display the current language name.
+ $form['language_information'] = array(
+ '#value' => t('Date format settings for %language_name', array('%language_name' => $language_name)),
+ '#prefix' =>'
',
+ '#suffix' =>'
',
+ );
+
+ // Get list of date format types.
+ $types = date_get_format_types();
+
+ // Get list of available formats.
+ $formats = date_get_formats();
+ $choices = array();
+ foreach ($formats as $type => $list) {
+ foreach ($list as $f => $format) {
+ $choices[$f] = date_format_date(date_now(), 'custom', $f);
+ }
+ }
+
+ // Get configured formats for each language.
+ $locale_formats = date_format_locale($langcode);
+ // Display a form field for each format type.
+ foreach ($types as $type => $type_info) {
+ if (!empty($locale_formats) && in_array($type, array_keys($locale_formats))) {
+ $default = $locale_formats[$type];
+ }
+ else {
+ $default = variable_get('date_format_' . $type, array_shift(array_keys($formats)));
+ }
+ include_once('./'. drupal_get_path('module', 'date_api') .'/date_api.admin.inc');
+ date_api_date_format_select_field($form, $type, $type_info, $default, $choices);
+ }
+
+ $form['buttons']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Save'),
+ '#submit' => array('date_locale_format_form_formats_submit'),
+ );
+ $form['buttons']['cancel'] = array(
+ '#type' => 'submit',
+ '#value' => t('Cancel'),
+ '#submit' => array('date_locale_format_form_formats_cancel'),
+ );
+ }
+
+ return $form;
+}
+
+/**
+ * Submit handler for choosing a language on the date_locale_format_form.
+ *
+ * @param $form
+ * Array, containing the form structure.
+ * @param &$form_state
+ * The 'rebuild' key inside $form_state['rebuild'] structure, overrides the
+ * 'redirect' key: when it is set to TRUE, the form will be rebuilt from
+ * scratch and displayed on screen.
+ */
+function date_locale_format_form_language_submit($form, &$form_state) {
+ $form_state['rebuild'] = TRUE;
+ $form_state['storage']['langcode'] = $form_state['values']['langcode'];
+}
+
+/**
+ * Submit handler for choosing a language on the date_locale_format_form.
+ */
+function date_locale_format_form_formats_submit($form, &$form_state) {
+ $langcode = $form_state['storage']['langcode'];
+
+ // Get list of date format types.
+ $types = date_get_format_types();
+ foreach ($types as $type => $type_info) {
+ $format = $form_state['values']['date_format_' . $type];
+ if ($format == 'custom') {
+ $format = $form_state['values']['date_format_' . $type . '_custom'];
+ }
+ date_locale_locale_format_save($langcode, $type, $format);
+ }
+ drupal_set_message(t('Configuration saved.'));
+ $form_state['storage'] = FALSE;
+ $form_state['rebuild'] = FALSE;
+ $form_state['redirect'] = 'admin/settings/date-time/locale';
+}
+
+/**
+ * 'Cancel' button handler for choosing a language on the
+ * date_locale_format_form.
+ */
+function date_locale_format_form_formats_cancel($form, &$form_state) {
+ $form_state['storage'] = FALSE;
+ $form_state['rebuild'] = FALSE;
+ $form_state['redirect'] = 'admin/settings/date-time/locale';
+}
+
+/**
+ * Save locale specific date formats to the database.
+ *
+ * @param $langcode
+ * Language code, can be 2 characters, e.g. 'en' or 5 characters, e.g.
+ * 'en-CA'.
+ * @param $type
+ * Date format type, e.g. 'short', 'medium'.
+ * @param $format
+ * The date format string.
+ */
+function date_locale_locale_format_save($langcode, $type, $format) {
+ $locale_format = array();
+ $locale_format['language'] = $langcode;
+ $locale_format['type'] = $type;
+ $locale_format['format'] = $format;
+
+ $is_existing = db_result(db_query("SELECT COUNT(*) FROM {date_format_locale} WHERE language = '%s' AND type = '%s'", $langcode, $type));
+ if ($is_existing) {
+ $keys = array('type', 'language');
+ drupal_write_record('date_format_locale', $locale_format, $keys);
+ }
+ else {
+ drupal_write_record('date_format_locale', $locale_format);
+ }
+
+}
diff --git a/sites/all/modules/date/date_php4/date_php4.inc b/sites/all/modules/date/date_php4/date_php4.inc
new file mode 100644
index 0000000..a675fff
--- /dev/null
+++ b/sites/all/modules/date/date_php4/date_php4.inc
@@ -0,0 +1,1071 @@
+
+ * value => '2007-04-15 09:25'
+ * timezone => 'UTC'
+ */
+ function date_create($date_in = NULL, $timezone = NULL) {
+ if (empty($date_in) || strtolower($date_in) == 'now') {
+ // Create a current date for an empty value or 'now'.
+ $date_out = date_date('Y-m-d H:i:s', (time()), $timezone);
+ }
+ elseif (drupal_substr($date_in, 0, 1) == '@' && is_numeric(drupal_substr($date_in, 1))) {
+ // An number prefixed with '@' is interpreted as a timestamp.
+ $date_out = date_date('Y-m-d H:i', drupal_substr($date_in, 1), $timezone);
+ }
+ elseif (preg_match(DATE_REGEX_LOOSE, $date_in, $regs)) {
+ $year = date_pad(isset($regs[1]) ? $regs[1] : 0, 4);
+ $month = date_pad(isset($regs[2]) ? $regs[2] : 0);
+ $day = date_pad(isset($regs[3]) ? $regs[3] : 0);
+ $hour = date_pad(isset($regs[5]) ? $regs[5] : 0);
+ $minute = date_pad(isset($regs[6]) ? $regs[6] : 0);
+ $second = date_pad(isset($regs[7]) ? $regs[7] : 0);
+ $date_out = "$year-$month-$day $hour:$minute:$second";
+ }
+ else {
+ // Try to use strtotime, will only work on post-1970 dates.
+ // Only use it if the value is big enough that timezone conversions
+ // won't make it into a negative value.
+ $test = @strtotime($date_in .' '. $timezone);
+ if ($test > 86400) {
+ $date_out = date_date('Y-m-d H:i', $test, $timezone);
+ }
+ }
+ if (empty($date_out)) {
+ return NULL;
+ }
+ $date = new stdClass();
+ $date->value = $date_out;
+ $date->timestamp = date_datetime2timestamp($date->value, $timezone);
+ $date->timezone = $timezone;
+ return $date;
+ }
+}
+
+if (!function_exists('date_format')) {
+ require_once('./'. drupal_get_path('module', 'date_php4') .'/date_php4_calc.inc');
+/**
+ * PHP 4 equivalent for date_format().
+ *
+ * Some formats that work in PHP 5 won't work in PHP 4, many won't work for
+ * dates earlier than 1970. Filter out those that need special treatment.
+ * No translation done here because the PHP 5 date_format() function isn't
+ * doing any translation and we need to return identical values in both.
+ *
+ * @param object $date
+ * @param string $format
+ * @return string
+ * return formatted date
+ */
+ function date_format($date, $format) {
+ $php5_formats = array('N', 'o', 'e', 'P', 'c', '\\');
+ $timestamp = $date->timestamp;
+ $date_string = '';
+ $max = strlen($format);
+ for ($i = 0; $i < $max; $i++) {
+ $c = $format[$i];
+ if ($date->timezone == 'UTC' && abs($timestamp) <= 0x7FFFFFFF && !in_array($c, $php5_formats)) {
+ $date_string .= gmdate($c, $timestamp);
+ }
+ else{
+ switch ($c) {
+ case 'U':
+ $date_string .= $timestamp;
+ break;
+ case 'l':
+ case 'w':
+ case 'D':
+ $dow = date_dow(date_part_extract($date->value, 'day'),
+ date_part_extract($date->value, 'month'),
+ date_part_extract($date->value, 'year'));
+ if ($c == 'w') {
+ $date_string .= $dow;
+ }
+ elseif ($c == 'l') {
+ $days = date_week_days_untranslated();
+ $date_string .= $days[$dow];
+ }
+ elseif ($c == 'D') {
+ // There is no date_week_days_abbr_untranslated().
+ // This rule works for English, untranslated day names.
+ $days = date_week_days_abbr();
+ $date_string .= drupal_substr($days[$dow], 0, 3);
+ }
+ break;
+ case 'L':
+ $date_string .= date_is_leap_year(date_part_extract($date->value, 'year'));
+ break;
+ case 'z':
+ $date_string .= date_calc_julian_date(date_part_extract($date->value, 'day'),
+ date_part_extract($date->value, 'month'),
+ date_part_extract($date->value, 'year'));
+ break;
+ case 'N':
+ $w = date_date('w', $timestamp, $date->timezone);
+ $date_string .= $w != 0 ? $w : 7;
+ break;
+ case 'o':
+ $iso_week = date_calc_gregorian_to_ISO(date_part_extract($date->value, 'day'),
+ date_part_extract($date->value, 'month'),
+ date_part_extract($date->value, 'year'));
+ $iso = explode('-', $iso_week);
+ $date_string .= ($c == 'o') ? $iso[0] : $iso[1];
+ break;
+ case 'O':
+ $date_string .= sprintf('%s%02d%02d', (date_offset_get($date) < 0 ? '-' : '+'), abs(date_offset_get($date) / 3600), abs(date_offset_get($date) % 3600) / 60);
+ break;
+ case 'P':
+ $date_string .= sprintf('%s%02d:%02d', (date_offset_get($date) < 0 ? '-' : '+'), abs(date_offset_get($date) / 3600), abs(date_offset_get($date) % 3600) / 60);
+ break;
+ case 'e':
+ $date_string .= $date->timezone;
+ break;
+ case 'Z':
+ $date_string .= date_offset_get($date);
+ break;
+ case '\\':
+ $date_string .= $format[++$i];
+ break;
+ case 't':
+ $date_string .= date_calc_days_in_month(date_part_extract($date->value, 'month'),
+ date_part_extract($date->value, 'year'));
+ break;
+ case 'W':
+ $result = date_calc_gregorian_to_ISO(date_part_extract($date->value, 'day'),
+ date_part_extract($date->value, 'month'),
+ date_part_extract($date->value, 'year'));
+ $result = explode('-', $result);
+ $date_string .= $result[1];
+ default:
+ if (strpos('AaeDFlMTBcdGgHhIijLmNnOoPrSstUuwYyZz', $c) !== FALSE) {
+ $date_string .= date_date($c, $timestamp, $date->timezone);
+ }
+ else {
+ $date_string .= $c;
+ }
+ }
+ }
+ }
+ return $date_string;
+ }
+}
+
+/**
+ * PHP 4 equivalent for date_date_set().
+ *
+ * @param $date
+ * a date object returned by date_create().
+ * @param $year
+ * a new year.
+ * @param $month
+ * a new month.
+ * @param $day
+ * a new day.
+ * @return $date
+ * the date objected updated for the new timezone.
+ *
+ */
+if (!function_exists('date_date_set')) {
+ function date_date_set(&$date, $year, $month, $day) {
+ $new_date = substr_replace($date->value, date_pad($year, 4), 0, 4);
+ $new_date = substr_replace($new_date, date_pad($month), 5, 2);
+ $new_date = substr_replace($new_date, date_pad($day), 8, 2);
+ $date = date_create($new_date, $date->timezone);
+ return $date;
+ }
+}
+
+/**
+ * PHP 4 equivalent for date_date_set().
+ *
+ * @param $date
+ * a date object returned by date_create().
+ * @param $year
+ * a new year.
+ * @param $month
+ * a new month.
+ * @param $day
+ * a new day.
+ * @return $date
+ * the date objected updated for the new timezone.
+ *
+ */
+if (!function_exists('date_time_set')) {
+ function date_time_set(&$date, $hour, $minute, $second) {
+ $new_date = substr_replace($date->value, date_pad($hour), 11, 2);
+ $new_date = substr_replace($new_date, date_pad($minute), 14, 2);
+ $new_date = substr_replace($new_date, date_pad($second), 16, 2);
+ $date = date_create($new_date, $date->timezone);
+ return $date;
+ }
+}
+
+if (!function_exists('date_timezone_set')) {
+/**
+ * PHP 4 equivalent for date_timezones_set().
+ *
+ * @param $date
+ * a date object returned by date_create().
+ * @param $timezone
+ * a new timezone for the date object.
+ * @return $date
+ * the date objected updated for the new timezone.
+ *
+ */
+ function date_timezone_set(&$date, $timezone) {
+ $date->timezone = $timezone;
+ $date->value = date_date(DATE_FORMAT_DATETIME, $date->timestamp, $timezone);
+ return $date;
+ }
+}
+
+if (!function_exists('timezone_open')) {
+/**
+ * PHP 4 equivalent for timezone_open().
+ * Just track the timezone name.
+ */
+ function timezone_open($timezone) {
+ return $timezone;
+ }
+}
+
+if (!function_exists('timezone_name_get')) {
+/**
+ * PHP 4 equivalent for timezone_name_get().
+ */
+ function timezone_name_get($timezone) {
+ return $timezone;
+ }
+}
+
+if (!function_exists('date_timezone_get')) {
+/**
+ * PHP 4 equivalent for date_timezone_get().
+ */
+ function date_timezone_get($date) {
+ return $date->timezone;
+ }
+}
+
+if (!function_exists('timezone_offset_get')) {
+/**
+ * PHP 4 equivalent for timezone_offset_get().
+ *
+ * Cache results for expensive process of getting offsets for each timezone.
+ * Each cached timezone array will show whether the timezone has dst and the
+ * dst and non-dst offset for that timezone.
+ *
+ * @param $timezone
+ * a timezone returned by timezone_open().
+ * @param $date
+ * a date object returned by date_create().
+ * @return $offset
+ * the offset in seconds for the supplied date object.
+ */
+ function timezone_offset_get($timezone, $date) {
+ if (empty($timezone) || $timezone == 'UTC' || !date_timezone_is_valid($timezone)) {
+ return 0;
+ }
+ static $zones = array(), $offsets = array();
+ if (!in_array($timezone, $zones)) {
+ $cached = cache_get('date_timezone_offsets:'. $timezone);
+ $offsets[$timezone] = isset($cached->data) ? $cached->data : array();
+ $zones[] = $timezone;
+ if (empty($offsets[$timezone])) {
+ $offsets[$timezone] = array('dst' => 0);
+ $zones = timezone_abbreviations_list();
+ foreach ($zones as $key => $abbr) {
+ foreach ($abbr as $zone) {
+ if ($zone['timezone_id'] == $timezone && $zone['dst'] == 1 && !isset($offsets[$timezone]['dst_offset'])) {
+ $offsets[$timezone]['dst_offset'] = $zone['offset'];
+ $offsets[$timezone]['dst'] = 1;
+ }
+ elseif ($zone['timezone_id'] == $timezone && $zone['dst'] != 1 && !isset($offsets[$timezone]['offset'])) {
+ $offsets[$timezone]['offset'] = $zone['offset'];
+ }
+ }
+ }
+ cache_set('date_timezone_offsets:'. $timezone, $offsets[$timezone]);
+ }
+ }
+ $timestamp = $date->timestamp;
+ if ($offsets[$timezone]['dst'] == 1) {
+ if (date_is_dst($timestamp, $timezone, $offsets[$timezone]['dst'])) {
+ return $offsets[$timezone]['dst_offset'];
+ }
+ }
+ return $offsets[$timezone]['offset'];
+ }
+}
+
+if (!function_exists('date_offset_get')) {
+/**
+ * PHP 4 equivalent for date_offset_get().
+ *
+ * Cache results for expensive process of getting offsets for each timezone.
+ * Each cached timezone array will show whether the timezone has dst and the
+ * dst and non-dst offset for that timezone.
+ *
+ * @param $date
+ * a date object returned by date_create().
+ * @return $offset
+ * the offset in seconds for the supplied date object.
+ */
+ function date_offset_get($date) {
+ return timezone_offset_get(timezone_open($date->timezone), $date);
+ }
+}
+
+if (!function_exists('date_modify')) {
+ require_once('./'. drupal_get_path('module', 'date_php4') .'/date_php4_calc.inc');
+/**
+ * A limited set of options are provided here to modify dates.
+ * Uses strtotime() on dates after 1970. Uses date_php4_calc.inc to do
+ * calculations on older dates.
+ *
+ * Will work for things like date_modify($date, '+1 Sunday');
+ *
+ * @param $date
+ * a date object created by date_create() to use as a reference
+ * point for the calculation.
+ * @param $change
+ * something like following phrases:
+ * '+1 day|week|month|year|Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday'
+ * '-3 day|week|month|year|Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday'
+ *
+ * @return
+ * the date that matches the phrase.
+ *
+ */
+ function date_modify(&$date, $change) {
+ $cdate = $date->value;
+ $time = drupal_substr($date->value, 11, 8);
+
+ // We have to use strings like 'First Sunday' instead of
+ // +1 Sunday to overcome a PHP5 bug (see #369020).
+ // Swap those values out here and go back to '+1 Sunday',
+ // the code that works in PHP4.
+ $replace = array_flip(date_order());
+ $change = strtr($change, $replace);
+
+ $change = trim($change);
+ //Date is too old for strtotime(), or looking for custom +/- values, use date_calc instead.
+ if (drupal_substr($change, 0, 1) != '+' && drupal_substr($change, 0, 1) != '-'
+ && 1971 < date_part_extract($cdate, 'year')
+ && date_part_extract($cdate, 'year') < 2038) {
+ $cdate = strtotime($change, strtotime($cdate .' UTC'));
+ // strtotime will sometimes end up with a bogus adjustment for daylight
+ // savings time, so compute the date and force them time back to the original.
+ $date->value = substr_replace(date_date(DATE_FORMAT_DATETIME, $cdate, $date->timezone), $time, 11);
+ }
+ else {
+ $days = date_week_days_untranslated();
+ $dows = array_flip($days);
+ preg_match('/([+|-])\s?([0-9]{1,32})\s?([day(s)?|week(s)?|month(s)?|year(s)?|hour(s)?|minute(s)?|second(s)?|Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday]{1,10})/', $change, $results);
+ $direction = $results[1];
+ $count = $results[2];
+ $item = $results[3];
+ if (empty($results) || empty($item)) {
+ return;
+ }
+ if (drupal_substr($item, -1) == 's') {
+ $item = drupal_substr($item, 0, strlen($item) - 1);
+ }
+ // Process +/- Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday
+ if (in_array($item, $days)) {
+ $dow = $dows[$item];
+ if ($direction == '+') {
+ $function = 'date_calc_next_day_of_week';
+ }
+ else {
+ $function = 'date_calc_prev_day_of_week';
+ }
+ for ($i = 1; $i <= $count; $i++) {
+ $cdate = $function($dow,
+ date_part_extract($cdate, 'day'),
+ date_part_extract($cdate, 'month'),
+ date_part_extract($cdate, 'year'));
+ }
+ $date->value = $cdate .' '. $time;
+ }
+ elseif ($item == 'day') {
+ if ($direction == '+') {
+ $function = 'date_calc_next_day';
+ }
+ else {
+ $function = 'date_calc_prev_day';
+ }
+ for ($i = 1; $i <= $count; $i++) {
+ $cdate = $function(date_part_extract($cdate, 'day'),
+ date_part_extract($cdate, 'month'),
+ date_part_extract($cdate, 'year'));
+ }
+ $date->value = $cdate .' '. $time;
+ }
+ elseif ($item == 'month') {
+ if ($direction == '+') {
+ $function = 'date_calc_begin_of_month_by_span';
+ }
+ else {
+ $function = 'date_calc_end_of_month_by_span';
+ }
+ // Find the next end or beginning of month that matches the search.
+ $day = date_part_extract($cdate, 'day');
+ $cdate = $function($direction . $count, date_part_extract($cdate, 'month'), date_part_extract($cdate, 'year'));
+ // Construct a new date with the current day of the month and the new month and year.
+ $mon = date_part_extract($cdate, 'month');
+ $year = date_part_extract($cdate, 'year');
+ $date->value = date_pad($year, 4) .'-'. date_pad($mon) .'-'. date_pad($day) .' '. $time;
+ }
+ elseif ($item == 'week') {
+ $dow = date_day_of_week($date);
+ if ($direction == '+') {
+ $function = 'date_calc_begin_of_next_week';
+ }
+ else {
+ $function = 'date_calc_begin_of_prev_week';
+ }
+ // Move to right week.
+ for ($i = 1; $i <= $count; $i++) {
+ $cdate = $function(date_part_extract($cdate, 'day'),
+ date_part_extract($cdate, 'month'),
+ date_part_extract($cdate, 'year'));
+ }
+ // Move to the right day of the week, if we're not looking for the first day.
+ if ($dow != variable_get('date_first_day', 1)) {
+ for ($i = 1; $i <= $dow; $i++) {
+ $cdate = date_calc_next_day(date_part_extract($cdate, 'day'),
+ date_part_extract($cdate, 'month'),
+ date_part_extract($cdate, 'year'));
+ }
+ }
+ $date->value = $cdate .' '. $time;
+ }
+ elseif ($item == 'year') {
+ // Move to the new year.
+ $year = date_part_extract($cdate, 'year');
+ for ($i = 1; $i <= $count; $i++) {
+ if ($direction == '+') {
+ $year++;
+ }
+ else {
+ $year--;
+ }
+ }
+ // Construct a new date with the current day and month and the new year.
+ $day = date_part_extract($cdate, 'day');
+ $mon = date_part_extract($cdate, 'month');
+ $date->value = date_pad($year, 4) .'-'. date_pad($mon) .'-'. date_pad($day) .' '. $time;
+ }
+ else {
+ switch ($item) {
+ case 'hour':
+ $count = $count * 3600;
+ break;
+ case 'minute':
+ $count = $count * 60;
+ break;
+ }
+ switch ($direction) {
+ case '-':
+ $timestamp = $date->timestamp - $count;
+ break;
+ default:
+ $timestamp = $date->timestamp + $count;
+ }
+ $date->value = date_date('Y-m-d H:i:s', $timestamp, $date->timezone);
+ }
+ }
+ $date->timestamp = date_datetime2timestamp($date->value, $date->timezone);
+ return $date;
+ }
+}
+
+if (!function_exists('timezone_identifiers_list')) {
+/**
+ * PHP 4 equivalent for timezone_identifiers_list().
+ *
+ * Expanded array looks like:
+ * array(
+ * 0 => 'Africa/Abidjan',
+ * 1 => 'Africa/Accra',
+ * 2 => 'Africa/Addis_Ababa',
+ * ...
+ */
+ function timezone_identifiers_list() {
+ static $timezone_identifiers_list = array();
+ if (empty($timezone_identifiers_list)) {
+ include(drupal_get_path('module', 'date_php4') .'/date_php4_tz_identifiers.inc');
+ }
+ return $timezone_identifiers_list;
+ }
+}
+
+if (!function_exists('timezone_abbreviations_list')) {
+/**
+ * PHP 4 equivalent for timezone_abbreviations_list().
+ * Array keyed on timezone abbreviation.
+ *
+ * Expanded array looks like:
+ * array(
+ * 'cdt' => array(
+ * 0 => array(
+ * 'dst' => true,
+ * 'offset' => -18000,
+ * 'timezone_id' => 'America/Chicago',
+ * ),
+ * 1 => array(
+ * 'dst' => true,
+ * 'offset' => -14400,
+ * 'timezone_id' => 'America/Havana',
+ * )...
+ *
+ */
+ function timezone_abbreviations_list() {
+ static $timezone_abbreviations_list = array();
+ if (empty($timezone_abbreviations_list)) {
+ include(drupal_get_path('module', 'date_php4') .'/date_php4_tz_abbreviations_list.inc');
+ }
+ return $timezone_abbreviations_list;
+ }
+}
+
+/**
+ * Create a timestamp from a datetime value.
+ *
+ * Can't use date_convert() to turn datetime to unix within the
+ * PHP 4 emulation because it creates endless loops.
+ */
+function date_datetime2timestamp($datetime, $timezone) {
+ preg_match(DATE_REGEX_LOOSE, $datetime, $regs);
+ return date_mktime((isset($regs[5]) ? $regs[5] : 0), (isset($regs[6]) ? $regs[6] : 0), (isset($regs[7]) ? $regs[7] : 0), (isset($regs[2]) ? $regs[2] : 0), (isset($regs[3]) ? $regs[3] : 0), (isset($regs[1]) ? $regs[1] : 0), $timezone);
+}
+
+/**
+ * Check if time is in Daylight Savings Time
+ * Uses dst region code, as stored in the $timezone_map array
+ * from date_php4_tz_map.inc
+ *
+ * @param $timezone name
+ * @param $timestamp
+ * @return
+ * 0 or 1
+ */
+function date_is_dst($timestamp, $timezone = NULL) {
+ if (abs($timestamp) > 0x7FFFFFFF) {
+ return FALSE;
+ }
+ if (empty($timezone)) {
+ $timezone = date_default_timezone_name();
+ }
+
+ static $timezone_map = array();
+ if (empty($timezone_map)) {
+ include(drupal_get_path('module', 'date_php4') .'/date_php4_tz_map.inc');
+ }
+ $region = array_key_exists($timezone, $timezone_map) ? $timezone_map[$timezone]['dst_region'] : 0;
+
+ // This should really be done with date_date() to get the right timezone
+ // adjustment for the year, but that leads to circular code that won't
+ // work, so we're stuck with date(), which hopefully will create the right
+ // year in most cases.
+ $year = date('Y', $timestamp);
+
+ // Information on Daylight Saving time was obtained from http://webexhibits.org/daylightsaving/g.html
+ // Note that 'last sunday' is interpreted as 'the last sunday before...'.
+ switch ($region) {
+ case 0:
+ return 0;
+ case 1: // Egypt
+ // start of DST (last Friday in April)
+ $dststart = strtotime("last friday UTC", strtotime("1 may $year UTC"));
+ // end of DST (last Thursday in September)
+ $dstend = strtotime("last thursday UTC", strtotime("1 october $year UTC"));
+ break;
+ case 2: // Namibia
+ // start of DST (first Sunday in September)
+ $dststart = strtotime("first sunday UTC", strtotime("1 september $year UTC"));
+ // end of DST (first Sunday April)
+ $dstend = strtotime("first sunday UTC", strtotime("1 april $year UTC"));
+ break;
+ case 3: // Former USSR
+ // start of DST (last Sunday in March)
+ $dststart = strtotime("last sunday UTC", strtotime("1 april $year UTC"));
+ // end of DST (last Sunday October)
+ $dstend = strtotime("last sunday UTC", strtotime("1 november $year UTC"));
+ break;
+ case 4: // Iraq, Syria
+ // start of DST (April 1st)
+ $dststart = strtotime("1 april $year UTC");
+ // end of DST (October 1st)
+ $dstend = strtotime("1 october $year UTC");
+ break;
+ case 5: // Israel
+ // start of DST (last Friday befor April 2nd, 2am)
+ $dststart = strtotime("-1 week friday GMT", strtotime("2 april $year GMT")) + 7200;
+ // end of DST (last sunday before 10th of tishray. see http://cgate.co.il/navigation/shaon_kaiz.htm.
+ switch ($year) {
+ case '2007':
+ $dstend = strtotime("-1 sunday GMT", strtotime("16 september $year GMT"))+ 7200;
+ break;
+ case '2008':
+ $dstend = strtotime("-1 sunday GMT",strtotime("9 october $year GMT"))+7200;
+ break;
+ case '2009':
+ $dstend = strtotime("-1 sunday GMT", strtotime("28 september $year GMT"))+ 7200;
+ break;
+ case '2010':
+ $dstend = strtotime("-1 sunday GMT", strtotime("18 september $year GMT"))+ 7200;
+ break;
+ case '2011':
+ $dstend = strtotime("-1 sunday GMT", strtotime("8 october $year GMT"))+ 7200;
+ break;
+ case '2012':
+ $dstend = strtotime("-1 sunday GMT", strtotime("26 september $year GMT"))+ 7200;
+ break;
+ case '2013':
+ $dstend = strtotime("-1 sunday GMT", strtotime("14 september $year GMT"))+ 7200;
+ break;
+ case '2014':
+ $dstend = strtotime("-1 sunday GMT", strtotime("4 october $year GMT"))+ 7200;
+ break;
+ case '2015':
+ $dstend = strtotime("-1 sunday GMT", strtotime("23 september $year GMT"))+ 7200;
+ break;
+ case '2016':
+ $dstend = strtotime("-1 sunday GMT", strtotime("12 october $year GMT"))+ 7200;
+ break;
+ default:
+ return FALSE;
+ }
+ break;
+ case 6: // Lebanon, Kirgizstan
+ // start of DST (Last Sunday in March)
+ $dststart = strtotime("last sunday UTC", strtotime("1 april $year UTC"));
+ // end of DST (Last Sunday in October)
+ $dstend = strtotime("last sunday UTC", strtotime("1 november $year UTC"));
+ break;
+ case 7: // Palestine
+ // start of DST (First Friday on or after April 15th)
+ $dststart = strtotime("next friday UTC", strtotime("14 april $year UTC"));
+ // end of DST (First Friday on or after October 15th)
+ $dstend = strtotime("next friday UTC", strtotime("14 october $year UTC"));
+ break;
+ case 8: // Iran
+ // start of DST (the first day of Farvardin (March 21))
+ $dststart = strtotime("21 march $year UTC");
+ // end of DST (the first day of Mehr (September 23))
+ $dstend = strtotime("23 september $year UTC");
+ break;
+ case 9: // South Australia
+ // start of DST (last Sunday in October)
+ $dststart = strtotime("last sunday UTC", strtotime("1 november $year UTC"));
+ // end of DST (last Sunday in March)
+ $dstend = strtotime("last sunday UTC", strtotime("1 april $year UTC"));
+ break;
+ case 10: // Australia, Tasmania
+ // start of DST (first Sunday in October)
+ $dststart = strtotime("first sunday UTC", strtotime("1 october $year UTC"));
+ // end of DST (last Sunday in March)
+ $dstend = strtotime("last sunday UTC", strtotime("1 april $year UTC"));
+ break;
+ case 11: // New Zealand
+ // start of DST (first Sunday in October)
+ $dststart = strtotime("first sunday UTC", strtotime("1 october $year UTC"));
+ // end of DST (first Sunday in April)
+ $dstend = strtotime("first sunday UTC", strtotime("1 april $year UTC"));
+ break;
+ case 12: // Tonga
+ // start of DST (first Sunday in November)
+ $dststart = strtotime("first sunday UTC", strtotime("1 november $year UTC"));
+ // end of DST (last Sunday in January)
+ $dstend = strtotime("last sunday UTC", strtotime("1 february $year UTC"));
+ break;
+ case 13: // EU and other European countries
+ // start of DST (last Sunday in March 1 am UTC)
+ $dststart = strtotime("last sunday UTC", strtotime("1 april $year UTC"));
+ // end of DST in Europe (last Sunday in October 1 am UTC)
+ $dstend = strtotime("last sunday UTC", strtotime("1 november $year UTC"));
+ break;
+ case 14: // Russian Federation
+ // start of DST (last Sunday in March 2 am local time)
+ $dststart = strtotime("last sunday UTC", strtotime("1 april $year UTC"));
+ // end of DST (last Sunday in October 2 am local time)
+ $dstend = strtotime("last sunday UTC", strtotime("1 november $year UTC"));
+ break;
+ case 15: // Northern America (where applicable)
+ // start of DST (where applicable) (first Sunday in April before 2007,
+ // after that second Sunday in March, 2 am local time)
+ if ($year < 2007) {
+ $dststart = strtotime("first sunday UTC", strtotime("1 april $year UTC"));
+ }
+ else {
+ $dststart = strtotime("second sunday UTC", strtotime("1 march $year UTC"));
+ }
+ // end of DST (where applicable) (last Sunday in October 2 am local time)
+ if ($year < 2007) {
+ $dstend = strtotime("last sunday UTC", strtotime("1 november $year UTC"));
+ }
+ else {
+ $dstend = strtotime("first sunday UTC", strtotime("1 november $year UTC"));
+ }
+ break;
+ case 16: // Cuba
+ // start of DST (April 1st)
+ $dststart = strtotime("1 april $year UTC");
+ // end of DST (last Sunday in October)
+ $dstend = strtotime("last sunday UTC", strtotime("1 november $year UTC"));
+ break;
+ case 17: // Brazil
+ // start of DST (first Sunday in November)
+ $dststart = strtotime("first sunday UTC", strtotime("1 november $year UTC"));
+ // end of DST (third Sunday in February)
+ $dstend = strtotime("third sunday UTC", strtotime("1 february $year UTC"));
+ break;
+ case 18: // Chile
+ // start of DST (Second Saturday of October - at midnight)
+ $dststart = strtotime("second saturday UTC", strtotime("1 october $year UTC"));
+ // end of DST (Second Saturday of March - at midnight)
+ $dstend = strtotime("second sunday UTC", strtotime("1 march $year UTC"));
+ break;
+ case 19: // Falklands
+ // start of DST (First Sunday on or after 8 September)
+ $dststart = strtotime("next sunday UTC", strtotime("7 september $year UTC"));
+ // end of DST (First Sunday on or after 6 April)
+ $dstend = strtotime("next sunday UTC", strtotime("5 april $year UTC"));
+ break;
+ case 20: // Paraguay
+ // start of DST (first Sunday in September)
+ $dststart = strtotime("first sunday UTC", strtotime("1 september $year UTC"));
+ // end of DST (first Sunday in April)
+ $dstend = strtotime("first sunday UTC", strtotime("1 april $year UTC"));
+ break;
+ }
+ // Have to use reverse logic in southern hemisphere.
+ $southern = array(9, 10, 11, 12, 17, 18, 19, 20);
+ if (in_array($region, $southern)) {
+ return !($timestamp <= $dststart && $dstend <= $timestamp);
+ }
+ else {
+ return ($dststart <= $timestamp && $timestamp <= $dstend);
+ }
+}
+
+/**
+ * @ingroup adodb
+ * @{
+ */
+/**
+ * Functions to handle mktime(), date(), and getdate() for dates outside the
+ * normal range. Uses native php date functions when possible, alterate
+ * methods when native functions won't work.
+ *
+ * Without these functions date(), mktime(), and getdate() won't work on
+ * dates prior to 1970 in PHP 4 or on dates prior to 1901 in PHP 5.
+ *
+ * Replace native php functions:
+ * getdate() with date_getdate()
+ * date() with date_date()
+ * gmdate() with date_gmdate()
+ * mktime() with date_mktime()
+ * gmmktime() with gmdate_mktime()
+ *
+ * Note: Dates earlier than 1582 need a Gregorian correction applied, which
+ * works correctly if only applied once. If the same early date is run through
+ * these functions more than once, the Gregorian correction may get duplicated
+ * or undone and not work correctly.
+ *
+ * The solution in PHP 5 is to use date_create() and date_format() for very old
+ * dates, which will correctly handle that adjustment. There is no foolproof
+ * workaround for PHP 4. PHP 5 date_create() and date_format() functions
+ * will also handle dates earlier than 100.
+ *
+ * The following functions were derived from code obtained from
+ * http://phplens.com/phpeverywhere/adodb_date_library, licensed as follows:
+ *
+ * COPYRIGHT(c) 2003-2005 John Lim
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted under the terms of the BSD License.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once('./'. drupal_get_path('module', 'date_php4') .'/date_php4_lib.inc');
+
+/**
+ * Returns an array with date info.
+ *
+ * @param $timestamp
+ * A unix timestamp.
+ * @param $timezone name
+ * Use 'UTC' to avoid timezone conversion.
+ */
+function date_getdate($timestamp = FALSE, $timezone = FALSE) {
+ return _date_getdate($timestamp, $timezone);
+}
+
+/**
+ * Like date_getdate with no GMT conversion.
+ */
+function date_gmgetdate($timestamp = FALSE) {
+ if (!$timestamp) return array();
+ $array = date_getdate($timestamp, 'UTC');
+ $array[0] = $timestamp;
+ return $array;
+}
+
+/**
+ * Return formatted date based on timestamp $timestamp.
+ *
+ * @param $format
+ * the format to be used for the returned timestamp
+ * @param $timestamp
+ * a unix timestamp
+ * @param $timezone name
+ * Use 'UTC' to avoid timezone conversion.
+ */
+function date_date($format, $timestamp = FALSE, $timezone = FALSE) {
+ // date($format) will adjust to the server timezone, which may
+ // not be right, but we don't use it in this module anywhere and
+ // there is no easy way to get it working right without creating
+ // circular code.
+ if ($timestamp === FALSE) return ($is_gmt)? @gmdate($format): @date($format);
+ if ($timezone === FALSE) {
+ $timezone = date_default_timezone_name();
+ }
+ // Anything with a timezone other than UTC needs to be forced to the
+ // low level function to compute the timezone offset correctly.
+ $is_gmt = $timezone == 'UTC' ? TRUE : FALSE;
+ if (abs($timestamp) <= 0x7FFFFFFF) {
+ // Below PHP 5.2 in windows, must be positive integer
+ if ($timestamp >= 0 && $is_gmt) {
+ return @gmdate($format, $timestamp);
+ }
+ elseif ($timestamp >= 0 && variable_get('date_use_server_zone', FALSE)) {
+ return @date($format, $timestamp);
+ }
+ }
+ return _date_date($format, $timestamp, $timezone);
+}
+
+/**
+ * Like date_date with no GMT conversion.
+ */
+function date_gmdate($format, $timestamp = FALSE, $test = FALSE) {
+ return date_date($format, $timestamp, 'UTC', $test);
+}
+
+/**
+ * Return a timestamp given a local time.
+ *
+ * @param $timezone name
+ * Use 'UTC' to avoid timezone conversion.
+ *
+ * Force anything that will require timezone conversion to use
+ * lower level functions to make sure we adjust to the right timezone
+ * (native 'date' functions use the server timezone).
+ */
+function date_mktime($hr, $min, $sec, $mon = FALSE, $day = FALSE, $year = FALSE, $timezone = FALSE) {
+ if ($timezone === FALSE) {
+ $timezone = date_default_timezone_name();
+ }
+ $is_gmt = $timezone == 'UTC' ? TRUE : FALSE;
+ $hr = intval($hr);
+ $min = intval($min);
+ $sec = intval($sec);
+ if ($mon === FALSE && $is_gmt) {
+ return @gmmktime($hr, $min, $sec);
+ }
+ $mon = intval($mon) > 0 ? intval($mon) : date('n');
+ $day = intval($day) > 0 ? intval($day) : date('j');
+ $year = intval($year) > 0 ? intval($year) : date('Y');
+
+ // Don't use native handling for any values that could create negative
+ // timestamp, Windows does not support them at all in PHP 4, and
+ // the adodb date library notes that since RedHat 7.3, negative
+ // timestamps are not supported in glibc either.
+ // Step in one year on either side of allowable 1970-2038 window
+ // to be sure timezone adjustments and month and day additions
+ // won't push our date outside this window.
+ if (1971 < $year && $year < 2037 && $is_gmt) {
+ return @gmmktime($hr, $min, $sec, $mon, $day, $year);
+ }
+
+ return _date_mktime($hr, $min, $sec, $mon, $day, $year, $timezone);
+}
+
+/**
+ * Like date_mktime with no GMT conversion.
+*/
+function date_gmmktime($hr, $min, $sec, $mon = FALSE, $day = FALSE, $year = FALSE) {
+ return date_mktime($hr, $min, $sec, $mon, $day, $year, 'UTC');
+}
+
+/**
+ * Get local time zone offset from GMT.
+ *
+ * @return timezone offset in seconds
+ */
+function date_get_gmt_diff_ts($timestamp, $timezone = NULL) {
+ if ($timezone == 'UTC') {
+ return 0;
+ }
+ elseif (empty($timezone)) {
+ $timezone = date_default_timezone_name();
+ }
+ $date = new stdClass();
+ $date->timestamp = $timestamp;
+ $date->timezone = $timezone;
+ return date_offset_get($date);
+}
+
+/**
+ * Fix 2-digit years. Works for any century. Assumes that if 2-digit is
+ * more than 30 years in future, then previous century.
+*/
+function date_year_digit_check($y) {
+ if ($y < 100) {
+ $yr = (integer) date("Y");
+ $century = (integer) ($yr /100);
+ if ($yr%100 > 50) {
+ $c1 = $century + 1;
+ $c0 = $century;
+ } else {
+ $c1 = $century;
+ $c0 = $century - 1;
+ }
+ $c1 *= 100;
+ // if 2-digit year is less than 30 years in future, set it to this century
+ // otherwise if more than 30 years in future, then we set 2-digit year to the prev century.
+ if (($y + $c1) < $yr + 30) $y = $y + $c1;
+ else $y = $y + $c0 * 100;
+ }
+ return $y;
+}
+
+/**
+ * Returns day of week for given date (0 = Sunday), works on dates outside
+ * normal date range.
+ *
+ * Adapted from a function in the ADODB date library by John Lim, more info in
+ * date_php4_lib.inc.
+ *
+ * @param int $day
+ * @param int $month
+ * @param int $year
+ * @return
+ * the number of the day in the week
+ */
+function date_dow($day, $month, $year) {
+ // Gregorian correction from ADODB
+ if ($year <= 1582) {
+ if ($year < 1582 ||
+ ($year == 1582 && ($month < 10 || ($month == 10 && $day < 15)))) $greg_correction = 3;
+ else
+ $greg_correction = 0;
+ } else
+ $greg_correction = 0;
+ if ($month > 2)
+ $month -= 2;
+ else {
+ $month += 10;
+ $year--;
+ }
+ $day = (floor((13 * $month - 1) / 5) +
+ $day + ($year % 100) +
+ floor(($year % 100) / 4) +
+ floor(($year / 100) / 4) - 2 *
+ floor($year / 100) + 77 + $greg_correction);
+ $weekday_number = $day - 7 * floor($day / 7);
+ return $weekday_number;
+}
+
+/**
+ * Returns true for a leap year, else FALSE. Works outside normal date range.
+ *
+ * @param int $year
+ * @return boolean
+ */
+function date_is_leap_year($year) {
+ if ($year < 1000) {
+ return FALSE;
+ }
+ if ($year < 1582) { // pre Gregorio XIII - 1582
+ return ($year % 4 == 0);
+ }
+ else { // post Gregorio XIII - 1582
+ return (($year % 4 == 0) && ($year % 100 != 0)) || ($year % 400 == 0);
+ }
+}
+
+/**
+ * @} End of ingroup "datelib".
+ */
diff --git a/sites/all/modules/date/date_php4/date_php4.info b/sites/all/modules/date/date_php4/date_php4.info
new file mode 100644
index 0000000..4c6cacf
--- /dev/null
+++ b/sites/all/modules/date/date_php4/date_php4.info
@@ -0,0 +1,12 @@
+name = Date PHP4
+description = Emulate PHP 5.2 date functions in PHP 4.x, PHP 5.0, and PHP 5.1. Required when using the Date API with PHP versions less than PHP 5.2.
+package = Date/Time
+dependencies[] = date_api
+core = 6.x
+
+; Information added by Drupal.org packaging script on 2014-03-31
+version = "6.x-2.10"
+core = "6.x"
+project = "date"
+datestamp = "1396284252"
+
diff --git a/sites/all/modules/date/date_php4/date_php4.install b/sites/all/modules/date/date_php4/date_php4.install
new file mode 100644
index 0000000..81810dd
--- /dev/null
+++ b/sites/all/modules/date/date_php4/date_php4.install
@@ -0,0 +1,16 @@
+ 'Date PHP4',
+ 'description' => 'Date PHP4 setup.',
+ 'access arguments' => array('administer date_php4 settings'),
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('date_php4_settings_form'),
+ 'type' => MENU_NORMAL_ITEM,
+ 'weight' => 6,
+ );
+ return $items;
+}
+
+/**
+ * Timezone handling.
+ */
+function date_php4_settings_form() {
+ drupal_set_title(t('Date PHP4 Settings'));
+ $form['date_use_server_zone'] = array(
+ '#type' => 'select',
+ '#options' => array(TRUE, t('TRUE'), FALSE => t('FALSE')),
+ '#default_value' => variable_get('date_use_server_zone', FALSE),
+ '#title' => t('Use PHP default timezone'),
+ '#description' => t('Getting date computations working correctly in PHP versions earlier than PHP 5.2 involves extra computations that add a lot of overhead. These computations are needed because the timezone PHP uses on date computations may not match the site or user timezone or other date-specific timezones. We can speed processing up if we assume that PHP is using the correct timezone, but need to do more time-intensive processing if it is not. If timezone adjustments do not seem to be working correctly in your setup, you can set this option to FALSE to force the system to use the more accurate, but slower, timezone computations.'),
+ );
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Save'),
+ );
+ return $form;
+}
+
+function date_php4_settings_form_submit($form, &$form_state) {
+ variable_set('date_use_server_zone', $form_state['values']['date_use_server_zone']);
+}
diff --git a/sites/all/modules/date/date_php4/date_php4_calc.inc b/sites/all/modules/date/date_php4/date_php4_calc.inc
new file mode 100644
index 0000000..d60d463
--- /dev/null
+++ b/sites/all/modules/date/date_php4/date_php4_calc.inc
@@ -0,0 +1,1498 @@
+
+ * %a abbreviated weekday name (Sun, Mon, Tue)
+ * %A full weekday name (Sunday, Monday, Tuesday)
+ * %b abbreviated month name (Jan, Feb, Mar)
+ * %B full month name (January, February, March)
+ * %d day of month (range 00 to 31)
+ * %e day of month, single digit (range 0 to 31)
+ * %E number of days since unspecified epoch (integer)
+ * (%E is useful for passing a date in a URL as
+ * an integer value. Then simply use
+ * date_calc_days_to_date() to convert back to a date.)
+ * %j day of year (range 001 to 366)
+ * %m month as decimal number (range 1 to 12)
+ * %n newline character (\n)
+ * %t tab character (\t)
+ * %w weekday as decimal (0 = Sunday)
+ * %U week number of current year, first sunday as first week
+ * %y year as decimal (range 00 to 99)
+ * %Y year as decimal including century (range 0000 to 9999)
+ * %% literal '%'
+ *
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param string $format
+ * The format string.
+ *
+ * @return string
+ * The date in the desired format.
+ */
+function date_calc_format($day, $month, $year, $format = DATE_CALC_FORMAT) {
+ if (!date_calc_is_valid($day, $month, $year)) {
+ $year = date_calc_date_now('%Y');
+ $month = date_calc_date_now('%m');
+ $day = date_calc_date_now('%d');
+ }
+ $output = '';
+ for ($strpos = 0; $strpos < strlen($format); $strpos++) {
+ $char = drupal_substr($format, $strpos, 1);
+ if ($char == '%') {
+ $nextchar = drupal_substr($format, $strpos + 1, 1);
+ switch ($nextchar) {
+ case 'a':
+ $output .= date_calc_get_weekday_abbrname($day, $month, $year);
+ break;
+ case 'A':
+ $output .= date_calc_get_weekday_fullname($day, $month, $year);
+ break;
+ case 'b':
+ $output .= date_calc_get_month_abbrname($month);
+ break;
+ case 'B':
+ $output .= date_calc_get_month_fullname($month);
+ break;
+ case 'd':
+ $output .= date_pad($day);
+ break;
+ case 'e':
+ $output .= $day;
+ break;
+ case 'E':
+ $output .= date_calc_date_to_days($day, $month, $year);
+ break;
+ case 'j':
+ $output .= date_calc_julian_date($day, $month, $year);
+ break;
+ case 'm':
+ $output .= date_pad($month);
+ break;
+ case 'n':
+ $output .= "\n";
+ break;
+ case 't':
+ $output .= "\t";
+ break;
+ case 'w':
+ $output .= date_dow($day, $month, $year);
+ break;
+ case 'U':
+ $output .= date_calc_week_of_year($day, $month, $year);
+ break;
+ case 'y':
+ $output .= drupal_substr(date_pad($year, 4), 2, 2);
+ break;
+ case 'Y':
+ $output .= date_pad($year, 4);
+ break;
+ case '%':
+ $output .= '%';
+ break;
+ default:
+ $output .= $char . $nextchar;
+ }
+ $strpos++;
+ }
+ else {
+ $output .= $char;
+ }
+ }
+ return $output;
+}
+
+/**
+ * Returns true for valid date, FALSE for invalid date.
+ * Renamed this function because we already have a similar function that
+ * expects a full date as a parameter.
+ *
+ * @param int $day
+ * the day of the month
+ * @param int $month
+ * the month
+ * @param int $year
+ * the year, using 2005, not 05. Do not add leading 0's for years prior to 1000.
+ *
+ * @return boolean
+ */
+function date_calc_is_valid($day, $month, $year) {
+ if ($year > variable_get('date_max_year', 4000) || $year < variable_get('date_min_year', 1)) {
+ return FALSE;
+ }
+ if (!checkdate($month, $day, $year)) {
+ // Checkdate won't work on very old dates in PHP 4, need more testing.
+ if (!date_gmmktime(0, 0, 0, $month, $day, $year)) {
+ return FALSE;
+ }
+ }
+ return true;
+}
+
+/**
+ * Converts a date to number of days since a distant unspecified epoch
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ *
+ * @return integer
+ * The number of days since the date_calc epoch.
+ */
+function date_calc_date_to_days($day, $month, $year) {
+ $century = (int)drupal_substr($year, 0, 2);
+ $year = (int)drupal_substr($year, 2, 2);
+ if ($month > 2) {
+ $month -= 3;
+ }
+ else {
+ $month += 9;
+ if ($year) {
+ $year--;
+ }
+ else {
+ $year = 99;
+ $century --;
+ }
+ }
+ return (floor((146097 * $century) / 4 ) +
+ floor((1461 * $year) / 4 ) +
+ floor((153 * $month + 2) / 5 ) +
+ $day + 1721119);
+}
+
+/**
+ * Converts number of days to a distant unspecified epoch
+ *
+ * @param int $days
+ * The number of days since the date_calc epoch.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return string
+ * The date in the desired format.
+ */
+function date_calc_days_to_date($days, $format = DATE_CALC_FORMAT) {
+ $days -= 1721119;
+ $century = floor((4 * $days - 1) / 146097);
+ $days = floor(4 * $days - 1 - 146097 * $century);
+ $day = floor($days / 4);
+
+ $year = floor((4 * $day + 3) / 1461);
+ $day = floor(4 * $day + 3 - 1461 * $year);
+ $day = floor(($day + 4) / 4);
+
+ $month = floor((5 * $day - 3) / 153);
+ $day = floor(5 * $day - 3 - 153 * $month);
+ $day = floor(($day + 5) / 5);
+
+ if ($month < 10) {
+ $month +=3;
+ }
+ else {
+ $month -=9;
+ if ($year++ == 99) {
+ $year = 0;
+ $century++;
+ }
+ }
+ $century = date_pad($century);
+ $year = date_pad($year);
+ return date_calc_format($day, $month, $century . $year, $format);
+}
+
+/**
+ * Converts from Gregorian Year-Month-Day to ISO Year-WeekNumber-WeekDay
+ *
+ * Uses ISO 8601 definitions. Algorithm by Rick McCarty, 1999 at
+ * http://personal.ecu.edu/mccartyr/ISOwdALG.txt .
+ * Transcribed to PHP by Jesus M. Castagnetto.
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ *
+ * @return string
+ * The date in ISO Year-WeekNumber-WeekDay format.
+ */
+function date_calc_gregorian_to_ISO($day, $month, $year) {
+ $mnth = array(0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
+ $y_isleap = date_is_leap_year($year);
+ $y_1_isleap = date_is_leap_year($year - 1);
+ $day_of_year_number = $day + $mnth[$month - 1];
+ if ($y_isleap && $month > 2) {
+ $day_of_year_number++;
+ }
+ // find Jan 1 weekday (monday = 1, sunday = 7)
+ $yy = ($year - 1) % 100;
+ $c = ($year - 1) - $yy;
+ $g = $yy + intval($yy / 4);
+ $jan1_weekday = 1 + intval((((($c / 100) % 4) * 5) + $g) % 7);
+ // weekday for year-month-day
+ $h = $day_of_year_number + ($jan1_weekday - 1);
+ $weekday = 1 + intval(($h - 1) % 7);
+ // find if Y M D falls in YearNumber Y-1, WeekNumber 52 or
+ if ($day_of_year_number <= (8 - $jan1_weekday) && $jan1_weekday > 4) {
+ $yearnumber = $year - 1;
+ if ($jan1_weekday == 5 || ($jan1_weekday == 6 && $y_1_isleap)) {
+ $weeknumber = 53;
+ }
+ else {
+ $weeknumber = 52;
+ }
+ }
+ else {
+ $yearnumber = $year;
+ }
+ // find if Y M D falls in YearNumber Y+1, WeekNumber 1
+ if ($yearnumber == $year) {
+ if ($y_isleap) {
+ $i = 366;
+ }
+ else {
+ $i = 365;
+ }
+ if (($i - $day_of_year_number) < (4 - $weekday)) {
+ $yearnumber++;
+ $weeknumber = 1;
+ }
+ }
+ // find if Y M D falls in YearNumber Y, WeekNumber 1 through 53
+ if ($yearnumber == $year) {
+ $j = $day_of_year_number + (7 - $weekday) + ($jan1_weekday - 1);
+ $weeknumber = intval($j / 7);
+ if ($jan1_weekday > 4) {
+ $weeknumber--;
+ }
+ }
+ // put it all together
+ if ($weeknumber < 10) {
+ $weeknumber = '0'. $weeknumber;
+ }
+ return $yearnumber .'-'. $weeknumber .'-'. $weekday;
+}
+
+/**
+ * Determines julian date of the given season
+ *
+ * Adapted from previous work in Java by James Mark Hamilton.
+ *
+ * @param string $season
+ * The season to get the date for:
+ * VERNALEQUINOX, SUMMERSOLSTICE, AUTUMNALEQUINOX, or WINTERSOLSTICE.
+ * @param string $year
+ * The year in four digit format. Must be between -1000BC and 3000AD.
+ *
+ * @return float
+ * The julian date the season starts on.
+ *
+ * @author James Mark Hamilton
+ * @author Robert Butler
+ */
+function date_calc_date_season($season, $year = 0) {
+ if ($year == '') {
+ $year = date_calc_get_year();
+ }
+ if (($year >= -1000) && ($year <= 1000)) {
+ $y = $year / 1000.0;
+ switch ($season) {
+ case 'VERNALEQUINOX':
+ $date_calc_julian_date = (((((((-0.00071 * $y) - 0.00111) * $y) + 0.06134) * $y) + 365242.1374) * $y) + 1721139.29189;
+ break;
+ case 'SUMMERSOLSTICE':
+ $date_calc_julian_date = (((((((0.00025 * $y) + 0.00907) * $y) - 0.05323) * $y) + 365241.72562) * $y) + 1721233.25401;
+ break;
+ case 'AUTUMNALEQUINOX':
+ $date_calc_julian_date = (((((((0.00074 * $y) - 0.00297) * $y) - 0.11677) * $y) + 365242.49558) * $y) + 1721325.70455;
+ break;
+ case 'WINTERSOLSTICE':
+ default:
+ $date_calc_julian_date = (((((((-0.00006 * $y) - 0.00933) * $y) - 0.00769) * $y) + 365242.88257) * $y) + 1721414.39987;
+ }
+ }
+ elseif (($year > 1000) && ($year <= 3000)) {
+ $y = ($year - 2000) / 1000;
+ switch ($season) {
+ case 'VERNALEQUINOX':
+ $date_calc_julian_date = (((((((-0.00057 * $y) - 0.00411) * $y) + 0.05169) * $y) + 365242.37404) * $y) + 2451623.80984;
+ break;
+ case 'SUMMERSOLSTICE':
+ $date_calc_julian_date = (((((((-0.0003 * $y) + 0.00888) * $y) + 0.00325) * $y) + 365241.62603) * $y) + 2451716.56767;
+ break;
+ case 'AUTUMNALEQUINOX':
+ $date_calc_julian_date = (((((((0.00078 * $y) + 0.00337) * $y) - 0.11575) * $y) + 365242.01767) * $y) + 2451810.21715;
+ break;
+ case 'WINTERSOLSTICE':
+ default:
+ $date_calc_julian_date = (((((((0.00032 * $y) - 0.00823) * $y) - 0.06223) * $y) + 365242.74049) * $y) + 2451900.05952;
+ }
+ }
+ return $date_calc_julian_date;
+}
+
+/**
+ * Returns the current local date.
+ *
+ * NOTE: This function retrieves the local date using strftime(),
+ * which may or may not be 32-bit safe on your system.
+ *
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return string
+ * The current date in the specified format.
+ */
+function date_calc_date_now($format = DATE_CALC_FORMAT) {
+ return strftime($format, time());
+}
+
+/**
+ * Returns the current local year in format CCYY.
+ *
+ * @param int $days
+ * An integer calculated by date_calc_date_to_days().
+ *
+ * @return string
+ * The current year in four digit format.
+ */
+function date_calc_get_year() {
+ return date_calc_date_now('%Y');
+}
+
+/**
+ * Returns the current local month in format MM
+ *
+ * @param int $days
+ * An integer calculated by date_calc_date_to_days().
+ *
+ * @return string
+ * The current month in two digit format.
+ */
+function date_calc_get_month() {
+ return date_calc_date_now('%m');
+}
+
+/**
+ * Returns the current local day in format DD
+ *
+ * @param int $days
+ * An integer calculated by date_calc_date_to_days().
+ *
+ * @return string
+ * The current day of the month in two digit format.
+ */
+function date_calc_get_day() {
+ return date_calc_date_now('%d');
+}
+
+/**
+ * Returns number of days since 31 December of year before given date.
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ *
+ * @return int
+ * The julian date for the date.
+ */
+function date_calc_julian_date($day = 0, $month = 0, $year = 0) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if (empty($day)) {
+ $day = date_calc_get_day();
+ }
+ $days = array(0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
+ $julian = ($days[$month - 1] + $day);
+ if ($month > 2 && date_is_leap_year($year)) {
+ $julian++;
+ }
+ return $julian;
+}
+
+/**
+ * Returns the full weekday name for the given date
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ *
+ * @return string
+ * The full name of the day of the week/
+ */
+function date_calc_get_weekday_fullname($day = 0, $month = 0, $year = 0) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if (empty($day)) {
+ $day = date_calc_get_day();
+ }
+ $weekday_names = date_week_days();
+ $weekday = date_dow($day, $month, $year);
+ return $weekday_names[$weekday];
+}
+
+/**
+ * Returns the abbreviated weekday name for the given date.
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The year. Use the complete year instead of the abbreviated version.
+ * E.g. use 2005, not 05. Do not add leading 0's for years prior to 1000.
+ * @param int $length
+ * The length of abbreviation.
+ *
+ * @return string
+ * The abbreviated name of the day of the week.
+ */
+function date_calc_get_weekday_abbrname($day = 0, $month = 0, $year = 0) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if (empty($day)) {
+ $day = date_calc_get_day();
+ }
+ $weekday_names = date_week_days_abbr();
+ $weekday = date_dow($day, $month, $year);
+ return $weekday_names[$weekday];
+}
+
+/**
+ * Returns the full month name for the given month.
+ *
+ * @param int $month
+ * The month.
+ *
+ * @return string
+ * The full name of the month.
+ */
+function date_calc_get_month_fullname($month) {
+ $month = (int)$month;
+ if (empty($month)) {
+ $month = (int)date_calc_get_month();
+ }
+ $month_names = date_month_names();
+ return $month_names[$month];
+}
+
+/**
+ * Returns the abbreviated month name for the given month.
+ *
+ * @param int $month
+ * The month.
+ * @param int $length
+ * The length of abbreviation.
+ *
+ * @return string
+ * The abbreviated name of the month.
+ */
+function date_calc_get_month_abbrname($month, $length = 3) {
+ $month = (int)$month;
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ return drupal_drupal_substr(date_calc_get_month_fullname($month), 0, $length);
+}
+
+/**
+ * Returns the numeric month from the month name or an abreviation
+ * Both August and Aug would return 8.
+ *
+ * @param string $month
+ * The name of the month to examine. Case insensitive.
+ *
+ * @return integer
+ * The month's number.
+ */
+function date_calc_get_month_from_fullname($month) {
+ $month = strtolower($month);
+ $months = date_month_names();
+ while (list($id, $name) = each($months)) {
+ if (ereg($month, strtolower($name))) {
+ return $id;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Returns week of the year, first Sunday is first day of first week.
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ *
+ * @return int
+ * The number of the week in the year.
+ */
+function date_calc_week_of_year($day = 0, $month = 0, $year = 0) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if (empty($day)) {
+ $day = date_calc_get_day();
+ }
+ $iso = date_calc_gregorian_to_ISO($day, $month, $year);
+ $parts = explode('-', $iso);
+ $week_number = intval($parts[1]);
+ return $week_number;
+}
+
+/**
+ * Returns quarter of the year for given date.
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ *
+ * @return int
+ * The number of the quarter in the year.
+ */
+function date_calc_quarter_of_year($day = 0, $month = 0, $year = 0) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if (empty($day)) {
+ $day = date_calc_get_day();
+ }
+ $year_quarter = intval(($month - 1) / 3 + 1);
+ return $year_quarter;
+}
+
+/**
+ * Find the number of days in the given month.
+ *
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ *
+ * @return int
+ * The number of days the month has.
+ */
+function date_calc_days_in_month($month = 0, $year = 0) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if ($year == 1582 && $month == 10) {
+ return 21; // October 1582 only had 1st-4th and 15th-31st
+ }
+ if ($month == 2) {
+ if (date_is_leap_year($year)) {
+ return 29;
+ }
+ else {
+ return 28;
+ }
+ }
+ elseif ($month == 4 or $month == 6 or $month == 9 or $month == 11) {
+ return 30;
+ }
+ else {
+ return 31;
+ }
+}
+
+/**
+ * Returns the number of rows on a calendar month. Useful for determining
+ * the number of rows when displaying a typical month calendar.
+ *
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ *
+ * @return int
+ * The number of weeks the month has.
+ */
+function date_calc_weeks_in_month($month = 0, $year = 0) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ $FDOM = date_calc_first_of_month_weekday($month, $year);
+ if (variable_get('date_first_day', 1)==1 && $FDOM==0) {
+ $first_week_days = 7 - $FDOM + variable_get('date_first_day', 1);
+ $weeks = 1;
+ }
+ elseif (variable_get('date_first_day', 1)==0 && $FDOM == 6) {
+ $first_week_days = 7 - $FDOM + variable_get('date_first_day', 1);
+ $weeks = 1;
+ }
+ else {
+ $first_week_days = variable_get('date_first_day', 1) - $FDOM;
+ $weeks = 0;
+ }
+ $first_week_days %= 7;
+ return ceil((date_calc_days_in_month($month, $year)
+ - $first_week_days) / 7) + $weeks;
+}
+
+/**
+ * Return an array with days in week.
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return array
+ * $week[$weekday].
+ */
+function date_calc_get_calendar_week($day = 0, $month = 0, $year = 0, $format = DATE_CALC_FORMAT) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if (empty($day)) {
+ $day = date_calc_get_day();
+ }
+ $week_array = array();
+ // date for the column of week
+ $curr_day = date_calc_begin_of_week($day, $month, $year, '%E');
+ for ($counter = 0; $counter <= 6; $counter++) {
+ $week_array[$counter] = date_calc_days_to_date($curr_day, $format);
+ $curr_day++;
+ }
+ return $week_array;
+}
+
+/**
+ * Return a set of arrays to construct a calendar month for the given date.
+ *
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return array
+ * $month[$row][$col].
+ */
+function date_calc_get_calendar_month($month = 0, $year = 0, $format = DATE_CALC_FORMAT) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ $month_array = array();
+ // date for the first row, first column of calendar month
+ if (variable_get('date_first_day', 1) == 1) {
+ if (date_calc_first_of_month_weekday($month, $year) == 0) {
+ $curr_day = date_calc_date_to_days('01', $month, $year) - 6;
+ }
+ else {
+ $curr_day = date_calc_date_to_days('01', $month, $year)
+ - date_calc_first_of_month_weekday($month, $year) + 1;
+ }
+ }
+ else {
+ $curr_day = (date_calc_date_to_days('01', $month, $year)
+ - date_calc_first_of_month_weekday($month, $year));
+ }
+ // number of days in this month
+ $date_calc_days_in_month = date_calc_days_in_month($month, $year);
+ $date_calc_weeks_in_month = date_calc_weeks_in_month($month, $year);
+ for ($row_counter = 0; $row_counter < $date_calc_weeks_in_month; $row_counter++) {
+ for ($column_counter = 0; $column_counter <= 6; $column_counter++) {
+ $month_array[$row_counter][$column_counter] =
+ date_calc_days_to_date($curr_day , $format);
+ $curr_day++;
+ }
+ }
+ return $month_array;
+}
+
+/**
+ * Return a set of arrays to construct a calendar year for the given date
+ *
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return array $year[$month][$row][$col]
+ */
+function date_calc_get_calendar_year($year = 0, $format = DATE_CALC_FORMAT) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ $year_array = array();
+ for ($curr_month = 0; $curr_month <= 11; $curr_month++) {
+ $year_array[$curr_month] =
+ date_calc_get_calendar_month($curr_month + 1,
+ $year, $format);
+ }
+ return $year_array;
+}
+
+/**
+ * Returns date of day before given date.
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return string
+ * The date in the desired format.
+ */
+function date_calc_prev_day($day = 0, $month = 0, $year = 0, $format = DATE_CALC_FORMAT) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if (empty($day)) {
+ $day = date_calc_get_day();
+ }
+ $days = date_calc_date_to_days($day, $month, $year);
+ return date_calc_days_to_date($days - 1, $format);
+}
+
+/**
+ * Returns date of day after given date
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return string
+ * The date in the desired format.
+ */
+function date_calc_next_day($day = 0, $month = 0, $year = 0, $format = DATE_CALC_FORMAT) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if (empty($day)) {
+ $day = date_calc_get_day();
+ }
+ $days = date_calc_date_to_days($day, $month, $year);
+ return date_calc_days_to_date($days + 1, $format);
+}
+
+/**
+ * Returns date of the previous weekday, skipping from Monday to Friday
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return string
+ * The date in the desired format.
+ */
+function date_calc_prev_weekday($day = 0, $month = 0, $year = 0, $format = DATE_CALC_FORMAT) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if (empty($day)) {
+ $day = date_calc_get_day();
+ }
+ $days = date_calc_date_to_days($day, $month, $year);
+ if (date_dow($day, $month, $year) == 1) {
+ $days -= 3;
+ }
+ elseif (date_dow($day, $month, $year) == 0) {
+ $days -= 2;
+ }
+ else {
+ $days -= 1;
+ }
+ return date_calc_days_to_date($days, $format);
+}
+
+/**
+ * Returns date of the next weekday of given date, skipping from
+ * Friday to Monday.
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return string
+ * The date in the desired format.
+ */
+function date_calc_next_weekday($day = 0, $month = 0, $year = 0, $format = DATE_CALC_FORMAT) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if (empty($day)) {
+ $day = date_calc_get_day();
+ }
+ $days = date_calc_date_to_days($day, $month, $year);
+ if (date_dow($day, $month, $year) == 5) {
+ $days += 3;
+ }
+ elseif (date_dow($day, $month, $year) == 6) {
+ $days += 2;
+ }
+ else {
+ $days += 1;
+ }
+ return date_calc_days_to_date($days, $format);
+}
+
+/**
+ * Returns date of the previous specific day of the week
+ * from the given date.
+ *
+ * @param int
+ * Day of week, 0=Sunday.
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param bool $on_or_before
+ * If true and days are same, returns current day.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return string
+ * The date in the desired format.
+ */
+function date_calc_prev_day_of_week($dow, $day = 0, $month = 0, $year = 0,
+ $format = DATE_CALC_FORMAT, $on_or_before = FALSE) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if (empty($day)) {
+ $day = date_calc_get_day();
+ }
+ $days = date_calc_date_to_days($day, $month, $year);
+ $curr_weekday = date_dow($day, $month, $year);
+ if ($curr_weekday == $dow) {
+ if (!$on_or_before) {
+ $days -= 7;
+ }
+ }
+ elseif ($curr_weekday < $dow) {
+ $days -= 7 - ($dow - $curr_weekday);
+ }
+ else {
+ $days -= $curr_weekday - $dow;
+ }
+ return date_calc_days_to_date($days, $format);
+}
+
+/**
+ * Returns date of the next specific day of the week
+ * from the given date.
+ *
+ * @param int $dow
+ * The day of the week (0 = Sunday).
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param bool $on_or_after
+ * If true and days are same, returns current day.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return string the date in the desired format
+ */
+function date_calc_next_day_of_week($dow, $day = 0, $month = 0, $year = 0,
+ $format = DATE_CALC_FORMAT, $on_or_after = FALSE) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if (empty($day)) {
+ $day = date_calc_get_day();
+ }
+ $days = date_calc_date_to_days($day, $month, $year);
+ $curr_weekday = date_dow($day, $month, $year);
+ if ($curr_weekday == $dow) {
+ if (!$on_or_after) {
+ $days += 7;
+ }
+ }
+ elseif ($curr_weekday > $dow) {
+ $days += 7 - ($curr_weekday - $dow);
+ }
+ else {
+ $days += $dow - $curr_weekday;
+ }
+ return date_calc_days_to_date($days, $format);
+}
+
+/**
+ * Find the month day of the beginning of week for given date,
+ * using variable_get('date_first_day', 1). Can return weekday of prev month.
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return string
+ * The date in the desired format.
+ */
+function date_calc_begin_of_week($day = 0, $month = 0, $year = 0,
+ $format = DATE_CALC_FORMAT) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if (empty($day)) {
+ $day = date_calc_get_day();
+ }
+ $this_weekday = date_dow($day, $month, $year);
+ $interval = (7 - variable_get('date_first_day', 1) + $this_weekday) % 7;
+ return date_calc_days_to_date(date_calc_date_to_days($day, $month, $year)
+ - $interval, $format);
+}
+
+/**
+ * Find the month day of the end of week for given date, using
+ * variable_get('date_first_day', 1). Can return weekday of following month.
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return string
+ * The date in the desired format.
+ */
+function date_calc_end_of_week($day = 0, $month = 0, $year = 0,
+ $format = DATE_CALC_FORMAT) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if (empty($day)) {
+ $day = date_calc_get_day();
+ }
+ $this_weekday = date_dow($day, $month, $year);
+ $interval = (6 + variable_get('date_first_day', 1) - $this_weekday) % 7;
+ return date_calc_days_to_date(date_calc_date_to_days($day, $month, $year)
+ + $interval, $format);
+}
+
+/**
+ * Find the month day of the beginning of week before given date, using
+ * variable_get('date_first_day', 1). Can return weekday of prev month.
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return string
+ * The date in the desired format.
+ */
+function date_calc_begin_of_prev_week($day = 0, $month = 0, $year = 0, $format = DATE_CALC_FORMAT) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if (empty($day)) {
+ $day = date_calc_get_day();
+ }
+ $date = date_calc_days_to_date(date_calc_date_to_days($day-7, $month, $year), '%Y%m%d');
+ $prev_week_year = intval(drupal_substr($date, 0, 4));
+ $prev_week_month = intval(drupal_substr($date, 4, 2));
+ $prev_week_day = intval(drupal_substr($date, 6, 2));
+ return date_calc_begin_of_week($prev_week_day, $prev_week_month, $prev_week_year, $format);
+}
+
+/**
+ * Find the month day of the beginning of week after given date, using
+ * variable_get('date_first_day', 1). Can return weekday of next month.
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return string the date in the desired format
+ */
+function date_calc_begin_of_next_week($day = 0, $month = 0, $year = 0,
+ $format = DATE_CALC_FORMAT) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if (empty($day)) {
+ $day = date_calc_get_day();
+ }
+ $date = date_calc_days_to_date(date_calc_date_to_days($day + 7, $month, $year), '%Y%m%d');
+ $next_week_year = intval(drupal_substr($date, 0, 4));
+ $next_week_month = intval(drupal_substr($date, 4, 2));
+ $next_week_day = intval(drupal_substr($date, 6, 2));
+ return date_calc_begin_of_week($next_week_day, $next_week_month, $next_week_year, $format);
+}
+
+/**
+ * Returns date of the first day of the month in the number of months
+ * from the given date
+ *
+ * @param int $months
+ * The number of months from the date provided.
+ * Positive numbers go into the future.
+ * Negative numbers go into the past.
+ * 0 is the month presented in $month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return string
+ * The date in the desired format.
+ */
+function date_calc_begin_of_month_by_span($months = 0, $month = 0, $year = 0, $format = DATE_CALC_FORMAT) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if ($months > 0) {
+ // future month
+ $tmp_mo = $month + $months;
+ $month = $tmp_mo % 12;
+ if ($month == 0) {
+ $month = 12;
+ $year = $year + floor(($tmp_mo - 1) / 12);
+ }
+ else {
+ $year = $year + floor($tmp_mo / 12);
+ }
+ }
+ else {
+ // past or present month
+ $tmp_mo = $month + $months;
+ if ($tmp_mo > 0) {
+ // same year
+ $month = $tmp_mo;
+ }
+ elseif ($tmp_mo == 0) {
+ // prior dec
+ $month = 12;
+ $year--;
+ }
+ else {
+ // some time in a prior year
+ $month = 12 + ($tmp_mo % 12);
+ $year = $year + floor($tmp_mo / 12);
+ }
+ }
+ return date_calc_format(1, $month, $year, $format);
+}
+
+/**
+ * Returns date of the last day of the month in the number of months
+ * from the given date.
+ *
+ * @param int $months
+ * The number of months from the date provided.
+ * Positive numbers go into the future.
+ * Negative numbers go into the past.
+ * 0 is the month presented in $month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return string
+ * The date in the desired format.
+ */
+function date_calc_end_of_month_by_span($months = 0, $month = 0, $year = 0, $format = DATE_CALC_FORMAT) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ if ($months > 0) {
+ // future month
+ $tmp_mo = $month + $months;
+ $month = $tmp_mo % 12;
+ if ($month == 0) {
+ $month = 12;
+ $year = $year + floor(($tmp_mo - 1) / 12);
+ }
+ else {
+ $year = $year + floor($tmp_mo / 12);
+ }
+ }
+ else {
+ // past or present month
+ $tmp_mo = $month + $months;
+ if ($tmp_mo > 0) {
+ // same year
+ $month = $tmp_mo;
+ }
+ elseif ($tmp_mo == 0) {
+ // prior dec
+ $month = 12;
+ $year--;
+ }
+ else {
+ // some time in a prior year
+ $month = 12 + ($tmp_mo % 12);
+ $year = $year + floor($tmp_mo / 12);
+ }
+ }
+ return date_calc_format(date_calc_days_in_month($month, $year), $month, $year, $format);
+}
+
+/**
+ * Find the day of the week for the first of the month of given date
+ *
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ *
+ * @return int
+ * Number of weekday for the first day, 0=Sunday.
+ */
+function date_calc_first_of_month_weekday($month = 0, $year = 0) {
+ if (empty($year)) {
+ $year = date_calc_get_year();
+ }
+ if (empty($month)) {
+ $month = date_calc_get_month();
+ }
+ return date_dow('01', $month, $year);
+}
+
+/**
+ * Calculates the date of the Nth weekday of the month,
+ * such as the second Saturday of January 2000
+ *
+ * @param int $week
+ * The number of the week to get (1 = first, etc. Also can be 'last'.)
+ * @param int $dow
+ * The day of the week (0 = Sunday).
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param string $format
+ * The string indicating how to format the output.
+ *
+ * @return string
+ * The date in the desired format.
+ */
+function date_calc_n_weekday_of_month($week, $dow, $month, $year, $format = DATE_CALC_FORMAT) {
+ if (is_numeric($week)) {
+ $DOW1day = ($week - 1) * 7 + 1;
+ $DOW1 = date_dow($DOW1day, $month, $year);
+ $wdate = ($week - 1) * 7 + 1 + (7 + $dow - $DOW1) % 7;
+ if ($wdate > date_calc_days_in_month($month, $year)) {
+ return -1;
+ }
+ else {
+ return date_calc_format($wdate, $month, $year, $format);
+ }
+ }
+ elseif ($week == 'last' && $dow < 7) {
+ $lastday = date_calc_days_in_month($month, $year);
+ $lastdow = date_dow($lastday, $month, $year);
+ $diff = $dow - $lastdow;
+ if ($diff > 0) {
+ return date_calc_format($lastday - (7 - $diff), $month, $year, $format);
+ }
+ else {
+ return date_calc_format($lastday + $diff, $month, $year, $format);
+ }
+ }
+ else {
+ return -1;
+ }
+}
+
+/**
+ * Determines if given date is a future date from now
+ *
+ * @param int $day
+ * The day of the month.
+ * @param int $month
+ * The month.
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ *
+ * @return boolean
+ */
+function date_calc_is_future_date($day, $month, $year) {
+ $this_year = date_calc_get_year();
+ $this_month = date_calc_get_month();
+ $this_day = date_calc_get_day();
+ if ($year > $this_year) {
+ return true;
+ }
+ elseif ($year == $this_year) {
+ if ($month > $this_month) {
+ return true;
+ }
+ elseif ($month == $this_month) {
+ if ($day > $this_day) {
+ return true;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Determines if given date is a past date from now
+ *
+ * @param int $day
+ * the day of the month
+ * @param int $month
+ * the month
+ * @param int $year
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ *
+ * @return boolean
+ */
+function date_calc_is_past_date($day, $month, $year) {
+ $this_year = date_calc_get_year();
+ $this_month = date_calc_get_month();
+ $this_day = date_calc_get_day();
+ if ($year < $this_year) {
+ return true;
+ }
+ elseif ($year == $this_year) {
+ if ($month < $this_month) {
+ return true;
+ }
+ elseif ($month == $this_month) {
+ if ($day < $this_day) {
+ return true;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Returns number of days between two given dates
+ *
+ * @param int $day1
+ * the day of the month
+ * @param int $month1
+ * the month
+ * @param int $year1
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param int $day2
+ * the day of the month
+ * @param int $month2
+ * the month
+ * @param int $year2
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ *
+ * @return int
+ * the absolute number of days between the two dates.
+ * If an error occurs, -1 is returned.
+ */
+function date_calc_date_diff($day1, $month1, $year1, $day2, $month2, $year2) {
+ if (!date_calc_is_valid($day1, $month1, $year1)) {
+ return -1;
+ }
+ if (!date_calc_is_valid($day2, $month2, $year2)) {
+ return -1;
+ }
+ return abs(date_calc_date_to_days($day1, $month1, $year1)
+ - date_calc_date_to_days($day2, $month2, $year2));
+}
+
+/**
+ * Compares two dates
+ *
+ * @param int $day1
+ * the day of the month
+ * @param int $month1
+ * the month
+ * @param int $year1
+ * The 4 digit year. Do not add leading 0's for years prior to 1000.
+ * @param int $day2
+ * the day of the month
+ * @param int $month2
+ * the month
+ * @param int $year2
+ * the year. Use the complete year instead of the abbreviated version.
+ * E.g. use 2005, not 05. Do not add leading 0's for years prior to 1000.
+ *
+ * @return int
+ * 0 if the dates are equal. 1 if date 1 is later, -1 if date 1 is earlier.
+ */
+function date_calc_compare_dates($day1, $month1, $year1, $day2, $month2, $year2) {
+ $ndays1 = date_calc_date_to_days($day1, $month1, $year1);
+ $ndays2 = date_calc_date_to_days($day2, $month2, $year2);
+ if ($ndays1 == $ndays2) {
+ return 0;
+ }
+ return ($ndays1 > $ndays2) ? 1 : -1;
+}
\ No newline at end of file
diff --git a/sites/all/modules/date/date_php4/date_php4_lib.inc b/sites/all/modules/date/date_php4/date_php4_lib.inc
new file mode 100644
index 0000000..e244a12
--- /dev/null
+++ b/sites/all/modules/date/date_php4/date_php4_lib.inc
@@ -0,0 +1,442 @@
+ 0,
+ 1960 => -315619200,
+ 1950 => -631152000,
+ 1940 => -946771200,
+ 1930 => -1262304000,
+ 1920 => -1577923200,
+ 1910 => -1893456000,
+ 1900 => -2208988800,
+ 1890 => -2524521600,
+ 1880 => -2840140800,
+ 1870 => -3155673600,
+ 1860 => -3471292800,
+ 1850 => -3786825600,
+ 1840 => -4102444800,
+ 1830 => -4417977600,
+ 1820 => -4733596800,
+ 1810 => -5049129600,
+ 1800 => -5364662400,
+ 1790 => -5680195200,
+ 1780 => -5995814400,
+ 1770 => -6311347200,
+ 1760 => -6626966400,
+ 1750 => -6942499200,
+ 1740 => -7258118400,
+ 1730 => -7573651200,
+ 1720 => -7889270400,
+ 1710 => -8204803200,
+ 1700 => -8520336000,
+ 1690 => -8835868800,
+ 1680 => -9151488000,
+ 1670 => -9467020800,
+ 1660 => -9782640000,
+ 1650 => -10098172800,
+ 1640 => -10413792000,
+ 1630 => -10729324800,
+ 1620 => -11044944000,
+ 1610 => -11360476800,
+ 1600 => -11676096000);
+
+ // The valid range of a 32bit signed timestamp is typically from
+ // Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT
+ //
+ $lastsecs = 0;
+ $lastyear = 1970;
+ foreach ($YRS as $year => $secs) {
+ if ($timestamp >= $secs) {
+ $a = $lastyear;
+ break;
+ }
+ $lastsecs = $secs;
+ $lastyear = $year;
+ }
+ $timestamp -= $lastsecs;
+ if (!isset($a)) $a = $lastyear;
+ for (; --$a >= 0;) {
+ $lastd = $timestamp;
+ if ($leap = date_is_leap_year($a)) $timestamp += $d366;
+ else $timestamp += $d365;
+
+ if ($timestamp >= 0) {
+ $year = $a;
+ break;
+ }
+ }
+ $secs_in_year = 86400 * ($leap ? 366 : 365) + $lastd;
+ $timestamp = $lastd;
+ $mtab = ($leap) ? $_month_table_leap : $_month_table_normal;
+ for ($a = 13 ; --$a > 0;) {
+ $lastd = $timestamp;
+ $timestamp += $mtab[$a] * $_day_power;
+ if ($timestamp >= 0) {
+ $month = $a;
+ $ndays = $mtab[$a];
+ break;
+ }
+ }
+ $timestamp = $lastd;
+ $day = $ndays + ceil(($timestamp+1) / ($_day_power));
+ $timestamp += ($ndays - $day+1)* $_day_power;
+ $hour = floor($timestamp/$_hour_power);
+ }
+ else {
+
+ if ($timezone != 'UTC') {
+ $timestamp += date_get_gmt_diff_ts($timestamp, $timezone);
+ }
+
+ for ($a = 1970 ;; $a++) {
+ $lastd = $timestamp;
+ if ($leap = date_is_leap_year($a)) $timestamp -= $d366;
+ else $timestamp -= $d365;
+ if ($timestamp < 0) {
+ $year = $a;
+ break;
+ }
+ }
+ $secs_in_year = $lastd;
+ $timestamp = $lastd;
+ $mtab = ($leap) ? $_month_table_leap : $_month_table_normal;
+ for ($a = 1 ; $a <= 12; $a++) {
+ $lastd = $timestamp;
+ $timestamp -= $mtab[$a] * $_day_power;
+ if ($timestamp < 0) {
+ $month = $a;
+ $ndays = $mtab[$a];
+ break;
+ }
+ }
+ $timestamp = $lastd;
+ $day = ceil(($timestamp + 1) / $_day_power);
+ $timestamp = $timestamp - ($day - 1) * $_day_power;
+ $hour = floor($timestamp / $_hour_power);
+ }
+ $timestamp -= $hour * $_hour_power;
+ $min = floor($timestamp / $_min_power);
+ $secs = $timestamp - $min * $_min_power;
+ $dow = date_dow($day, $month, $year);
+ return array(
+ 'second' => $secs,
+ 'minute' => $min,
+ 'hour' => $hour,
+ 'day' => $day,
+ 'wday' => $dow,
+ 'month' => $month,
+ 'year' => $year,
+ 'yday' => floor($secs_in_year / $_day_power),
+ 'weekday' => gmdate('l', ($_day_power * (3 + $dow))),
+ 'leap' => $leap,
+ 'ndays' => $ndays,
+ 'month_name' => gmdate('F', mktime(0, 0, 0, $month, 2, 1971)),
+ 0 => $timestamp_in
+ );
+}
+
+/**
+ * Low level function to create date() for pre-1970 and post-2038 dates.
+ *
+ * @param $format a format string for the result
+ * @param $timestamp a unix timestamp
+ * @param $timezone name
+ * Use 'UTC' to avoid timezone conversion.
+ */
+function _date_date($format, $timestamp = FALSE, $timezone = FALSE) {
+ if ($timezone === FALSE) {
+ $timezone = date_default_timezone_name();
+ }
+
+ $_day_power = 86400;
+ $arr = _date_getdate($timestamp, $timezone);
+ $year = $arr['year'];
+ $month = $arr['month'];
+ $day = $arr['day'];
+ $hour = $arr['hour'];
+ $min = $arr['minute'];
+ $secs = $arr['second'];
+ $max = strlen($format);
+ $dates = '';
+
+ /*
+ at this point, we have the following integer vars to manipulate:
+ $year, $month, $day, $hour, $min, $secs
+ */
+ for ($i = 0; $i < $max; $i++) {
+ switch ($format[$i]) {
+ case 'T': $dates .= date('T');break;
+ // YEAR
+ case 'L': $dates .= $arr['leap'] ? '1' : '0'; break;
+ case 'r': // Thu, 21 Dec 2000 16:01:07 +0200
+ // 4.3.11 uses '04 Jun 2004'
+ // 4.3.8 uses ' 4 Jun 2004'
+ $dates .= gmdate('D', $_day_power*(3 + date_dow($day, $month, $year))) .', '.
+ ($day < 10 ? '0'. $day : $day) .' '. date('M', mktime(0, 0, 0, $month, 2, 1971)) .' '. $year .' ';
+ if ($hour < 10) $dates .= '0'. $hour; else $dates .= $hour;
+ if ($min < 10) $dates .= ':0'. $min; else $dates .= ':'. $min;
+ if ($secs < 10) $dates .= ':0'. $secs; else $dates .= ':'. $secs;
+ $gmt = date_get_gmt_diff_ts($timestamp, $timezone);
+ $dates .= sprintf(' %s%04d', ($gmt >= 0) ? '+' : '-', abs($gmt) / 36); break;
+ case 'Y': $dates .= date_pad($year, 4); break;
+ case 'y': $dates .= drupal_substr($year, strlen($year)-2, 2); break;
+ // MONTH
+ case 'm': if ($month<10) $dates .= '0'. $month; else $dates .= $month; break;
+ case 'Q': $dates .= ($month + 3)>>2; break;
+ case 'n': $dates .= $month; break;
+ case 'M': $dates .= date('M', mktime(0, 0, 0, $month, 2, 1971)); break;
+ case 'F': $dates .= date('F', mktime(0, 0, 0, $month, 2, 1971)); break;
+ // DAY
+ case 't': $dates .= $arr['ndays']; break;
+ case 'z': $dates .= $arr['yday']; break;
+ case 'w': $dates .= date_dow($day, $month, $year); break;
+ case 'l': $dates .= gmdate('l', $_day_power*(3 + date_dow($day, $month, $year))); break;
+ case 'D': $dates .= gmdate('D', $_day_power*(3 + date_dow($day, $month, $year))); break;
+ case 'j': $dates .= $day; break;
+ case 'd': if ($day<10) $dates .= '0'. $day; else $dates .= $day; break;
+ case 'S':
+ $d10 = $day % 10;
+ if ($d10 == 1) $dates .= 'st';
+ elseif ($d10 == 2 && $day != 12) $dates .= 'nd';
+ elseif ($d10 == 3) $dates .= 'rd';
+ else $dates .= 'th';
+ break;
+ // HOUR
+ case 'Z':
+ $dates .= -date_get_gmt_diff_ts($timestamp, $timezone);
+ break;
+ case 'O':
+ $gmt = date_get_gmt_diff_ts($timestamp, $timezone);
+ $dates .= sprintf('%s%04d', ($gmt<0)?'+':'-', abs($gmt)/36);
+ break;
+ case 'H':
+ if ($hour < 10) $dates .= '0'. $hour;
+ else $dates .= $hour;
+ break;
+ case 'h':
+ if ($hour > 12) $hh = $hour - 12;
+ else {
+ if ($hour == 0) $hh = '12';
+ else $hh = $hour;
+ }
+ if ($hh < 10) $dates .= '0'. $hh;
+ else $dates .= $hh;
+ break;
+ case 'G':
+ $dates .= $hour;
+ break;
+ case 'g':
+ if ($hour > 12) $hh = $hour - 12;
+ else {
+ if ($hour == 0) $hh = '12';
+ else $hh = $hour;
+ }
+ $dates .= $hh;
+ break;
+ // MINUTES
+ case 'i': if ($min < 10) $dates .= '0'. $min; else $dates .= $min; break;
+ // SECONDS
+ case 'U': $dates .= $timestamp; break;
+ case 's': if ($secs < 10) $dates .= '0'. $secs; else $dates .= $secs; break;
+ // AM/PM
+ // Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM
+ case 'a':
+ if ($hour>=12) $dates .= 'pm';
+ else $dates .= 'am';
+ break;
+ case 'A':
+ if ($hour>=12) $dates .= 'PM';
+ else $dates .= 'AM';
+ break;
+ default:
+ $dates .= $format[$i]; break;
+ // ESCAPE
+ case "\\":
+ $i++;
+ if ($i < $max) $dates .= $format[$i];
+ break;
+ }
+ }
+ return $dates;
+}
+
+/**
+ * Low level function to create mktime() for pre-1970 and post 2038 dates.
+ *
+ * @param $hr the hour
+ * @param $min the minute
+ * @param $sec the second
+ * @param $mon the month
+ * @param $day the day
+ * @param $year the year
+ * @param $timezone name
+ * Use 'UTC' to avoid timezone conversion.
+ */
+function _date_mktime($hr, $min, $sec, $mon = FALSE, $day = FALSE, $year = FALSE, $timezone = FALSE) {
+ if ($timezone === FALSE) {
+ $timezone = date_default_timezone_name();
+ }
+
+ /*
+ # disabled because some people place large values in $sec.
+ # however we need it for $mon because we use an array...
+ $hr = intval($hr);
+ $min = intval($min);
+ $sec = intval($sec);
+ */
+ $mon = intval($mon);
+ $day = intval($day);
+ $year = intval($year);
+ $year = date_year_digit_check($year);
+ if ($mon > 12) {
+ $y = floor(($mon-1) / 12);
+ $year += $y;
+ $mon -= $y * 12;
+ }
+ elseif ($mon < 1) {
+ $y = ceil((1-$mon) / 12);
+ $year -= $y;
+ $mon += $y * 12;
+ }
+ $_day_power = 86400;
+ $_hour_power = 3600;
+ $_min_power = 60;
+ $_month_table_normal = array("", 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
+ $_month_table_leap = array("", 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
+ $_total_date = 0;
+ if ($year >= 1970) {
+ $year_in = $year;
+ for ($a = 1970 ; $a <= $year; $a++) {
+ $leap = date_is_leap_year($a);
+ if ($leap == true) {
+ $loop_table = $_month_table_leap;
+ $_add_date = 366;
+ }
+ else {
+ $loop_table = $_month_table_normal;
+ $_add_date = 365;
+ }
+ if ($a < $year) {
+ $_total_date += $_add_date;
+ }
+ else {
+ for ($b=1; $b<$mon; $b++) {
+ $_total_date += $loop_table[$b];
+ }
+ }
+ }
+ $_total_date +=$day-1;
+ $ret = ($_total_date * $_day_power) + ($hr * $_hour_power) + ($min * $_min_power) + $sec;
+ $ret -= date_get_gmt_diff_ts($ret, $timezone);
+
+ }
+ else {
+ for ($a = 1969 ; $a >= $year; $a--) {
+ $leap = date_is_leap_year($a);
+ if ($leap == true) {
+ $loop_table = $_month_table_leap;
+ $_add_date = 366;
+ }
+ else {
+ $loop_table = $_month_table_normal;
+ $_add_date = 365;
+ }
+ if ($a > $year) { $_total_date += $_add_date;
+ }
+ else {
+ for ($b = 12;$b>$mon;$b--) {
+ $_total_date += $loop_table[$b];
+ }
+ }
+ }
+ $_total_date += $loop_table[$mon] - $day;
+ $_day_time = $hr * $_hour_power + $min * $_min_power + $sec;
+ $_day_time = $_day_power - $_day_time;
+ $ret = -( $_total_date * $_day_power + $_day_time);
+ if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 Oct 1582 - gregorian correction
+ elseif ($ret < -12219321600) $ret = -12219321600; // if in limbo, reset to 15 Oct 1582.
+ }
+ return $ret;
+}
+
+/**
+ * @} End of ingroup "adodb".
+ */
\ No newline at end of file
diff --git a/sites/all/modules/date/date_php4/date_php4_missing_data.inc b/sites/all/modules/date/date_php4/date_php4_missing_data.inc
new file mode 100644
index 0000000..7171ca2
--- /dev/null
+++ b/sites/all/modules/date/date_php4/date_php4_missing_data.inc
@@ -0,0 +1,66 @@
+ 'Africa/Asmara',
+ 2 => 'Africa/Bujumbura',
+ 3 => 'Africa/Kinshasa',
+ 4 => 'Africa/Lome',
+ 5 => 'Africa/Lubumbashi',
+ 6 => 'America/Argentina/Buenos_Aires',
+ 7 => 'America/Argentina/Catamarca',
+ 8 => 'America/Argentina/ComodRivadavia',
+ 9 => 'America/Argentina/Cordoba',
+ 10 => 'America/Argentina/Jujuy',
+ 11 => 'America/Argentina/La_Rioja',
+ 12 => 'America/Argentina/Mendoza',
+ 13 => 'America/Argentina/Rio_Gallegos',
+ 14 => 'America/Argentina/San_Juan',
+ 15 => 'America/Argentina/Tucuman',
+ 16 => 'America/Argentina/Ushuaia',
+ 17 => 'America/Atikokan',
+ 18 => 'America/Bahia',
+ 19 => 'America/Blanc-Sablon',
+ 20 => 'America/Campo_Grande',
+ 21 => 'America/Coral_Harbour',
+ 22 => 'America/Indiana/Petersburg',
+ 23 => 'America/Indiana/Vincennes',
+ 24 => 'America/Indiana/Winamac',
+ 25 => 'America/Moncton',
+ 26 => 'America/North_Dakota/New_Salem',
+ 27 => 'America/Resolute',
+ 28 => 'America/Toronto',
+ 29 => 'Antarctica/Rothera',
+ 30 => 'Asia/Dili',
+ 31 => 'Asia/Macau',
+ 32 => 'Asia/Makassar',
+ 33 => 'Asia/Oral',
+ 34 => 'Asia/Qyzylorda',
+ 35 => 'Asia/Samarkand',
+ 36 => 'Asia/Tehran',
+ 37 => 'Atlantic/Faroe',
+ 38 => 'Atlantic/Jan_Mayen',
+ 39 => 'Atlantic/South_Georgia',
+ 40 => 'Australia/Currie',
+ 41 => 'Australia/Eucla',
+ 42 => 'Europe/Guernsey',
+ 43 => 'Europe/Isle_of_Man',
+ 44 => 'Europe/Jersey',
+ 45 => 'Europe/Mariehamn',
+ 46 => 'Europe/Podgorica',
+ 47 => 'Europe/Volgograd',
+ 48 => 'Indian/Christmas',
+ 49 => 'Indian/Cocos',
+ 50 => 'Pacific/Fakaofo',
+ 51 => 'Pacific/Funafuti',
+ 52 => 'Pacific/Johnston',
+ 53 => 'Pacific/Palau',
+ 54 => 'Pacific/Ponape',
+ 55 => 'Pacific/Port_Moresby',
+ 56 => 'Pacific/Tarawa',
+ 57 => 'Pacific/Truk',
+ 58 => 'Pacific/Wake',
+ 59 => 'Pacific/Wallis',
+ 60 => 'Pacific/Yap',
+);
diff --git a/sites/all/modules/date/date_php4/date_php4_tz_abbreviations_list.inc b/sites/all/modules/date/date_php4/date_php4_tz_abbreviations_list.inc
new file mode 100644
index 0000000..a59bd89
--- /dev/null
+++ b/sites/all/modules/date/date_php4/date_php4_tz_abbreviations_list.inc
@@ -0,0 +1,10 @@
+ array(
+ 'offset' => -43200000,
+ 'longname' => "GMT-12:00",
+ 'shortname' => 'GMT-12:00',
+ 'hasdst' => FALSE ),
+ 'Etc/GMT+11' => array(
+ 'offset' => -39600000,
+ 'longname' => "GMT-11:00",
+ 'shortname' => 'GMT-11:00',
+ 'hasdst' => FALSE ),
+ 'MIT' => array(
+ 'offset' => -39600000,
+ 'longname' => "West Samoa Time",
+ 'shortname' => 'WST',
+ 'hasdst' => FALSE ),
+ 'Pacific/Apia' => array(
+ 'offset' => -39600000,
+ 'longname' => "West Samoa Time",
+ 'shortname' => 'WST',
+ 'hasdst' => FALSE ),
+ 'Pacific/Midway' => array(
+ 'offset' => -39600000,
+ 'longname' => "Samoa Standard Time",
+ 'shortname' => 'SST',
+ 'hasdst' => FALSE ),
+ 'Pacific/Niue' => array(
+ 'offset' => -39600000,
+ 'longname' => "Niue Time",
+ 'shortname' => 'NUT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Pago_Pago' => array(
+ 'offset' => -39600000,
+ 'longname' => "Samoa Standard Time",
+ 'shortname' => 'SST',
+ 'hasdst' => FALSE ),
+ 'Pacific/Samoa' => array(
+ 'offset' => -39600000,
+ 'longname' => "Samoa Standard Time",
+ 'shortname' => 'SST',
+ 'hasdst' => FALSE ),
+ 'US/Samoa' => array(
+ 'offset' => -39600000,
+ 'longname' => "Samoa Standard Time",
+ 'shortname' => 'SST',
+ 'hasdst' => FALSE ),
+ 'America/Adak' => array(
+ 'offset' => -36000000,
+ 'longname' => "Hawaii-Aleutian Standard Time",
+ 'shortname' => 'HAST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Hawaii-Aleutian Daylight Time",
+ 'dstshortname' => 'HADT' ),
+ 'America/Atka' => array(
+ 'offset' => -36000000,
+ 'longname' => "Hawaii-Aleutian Standard Time",
+ 'shortname' => 'HAST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Hawaii-Aleutian Daylight Time",
+ 'dstshortname' => 'HADT' ),
+ 'Etc/GMT+10' => array(
+ 'offset' => -36000000,
+ 'longname' => "GMT-10:00",
+ 'shortname' => 'GMT-10:00',
+ 'hasdst' => FALSE ),
+ 'HST' => array(
+ 'offset' => -36000000,
+ 'longname' => "Hawaii Standard Time",
+ 'shortname' => 'HST',
+ 'hasdst' => FALSE ),
+ 'Pacific/Fakaofo' => array(
+ 'offset' => -36000000,
+ 'longname' => "Tokelau Time",
+ 'shortname' => 'TKT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Honolulu' => array(
+ 'offset' => -36000000,
+ 'longname' => "Hawaii Standard Time",
+ 'shortname' => 'HST',
+ 'hasdst' => FALSE ),
+ 'Pacific/Johnston' => array(
+ 'offset' => -36000000,
+ 'longname' => "Hawaii Standard Time",
+ 'shortname' => 'HST',
+ 'hasdst' => FALSE ),
+ 'Pacific/Rarotonga' => array(
+ 'offset' => -36000000,
+ 'longname' => "Cook Is. Time",
+ 'shortname' => 'CKT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Tahiti' => array(
+ 'offset' => -36000000,
+ 'longname' => "Tahiti Time",
+ 'shortname' => 'TAHT',
+ 'hasdst' => FALSE ),
+ 'SystemV/HST10' => array(
+ 'offset' => -36000000,
+ 'longname' => "Hawaii Standard Time",
+ 'shortname' => 'HST',
+ 'hasdst' => FALSE ),
+ 'US/Aleutian' => array(
+ 'offset' => -36000000,
+ 'longname' => "Hawaii-Aleutian Standard Time",
+ 'shortname' => 'HAST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Hawaii-Aleutian Daylight Time",
+ 'dstshortname' => 'HADT' ),
+ 'US/Hawaii' => array(
+ 'offset' => -36000000,
+ 'longname' => "Hawaii Standard Time",
+ 'shortname' => 'HST',
+ 'hasdst' => FALSE ),
+ 'Pacific/Marquesas' => array(
+ 'offset' => -34200000,
+ 'longname' => "Marquesas Time",
+ 'shortname' => 'MART',
+ 'hasdst' => FALSE ),
+ 'AST' => array(
+ 'offset' => -32400000,
+ 'longname' => "Alaska Standard Time",
+ 'shortname' => 'AKST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Alaska Daylight Time",
+ 'dstshortname' => 'AKDT' ),
+ 'America/Anchorage' => array(
+ 'offset' => -32400000,
+ 'longname' => "Alaska Standard Time",
+ 'shortname' => 'AKST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Alaska Daylight Time",
+ 'dstshortname' => 'AKDT' ),
+ 'America/Juneau' => array(
+ 'offset' => -32400000,
+ 'longname' => "Alaska Standard Time",
+ 'shortname' => 'AKST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Alaska Daylight Time",
+ 'dstshortname' => 'AKDT' ),
+ 'America/Nome' => array(
+ 'offset' => -32400000,
+ 'longname' => "Alaska Standard Time",
+ 'shortname' => 'AKST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Alaska Daylight Time",
+ 'dstshortname' => 'AKDT' ),
+ 'America/Yakutat' => array(
+ 'offset' => -32400000,
+ 'longname' => "Alaska Standard Time",
+ 'shortname' => 'AKST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Alaska Daylight Time",
+ 'dstshortname' => 'AKDT' ),
+ 'Etc/GMT+9' => array(
+ 'offset' => -32400000,
+ 'longname' => "GMT-09:00",
+ 'shortname' => 'GMT-09:00',
+ 'hasdst' => FALSE ),
+ 'Pacific/Gambier' => array(
+ 'offset' => -32400000,
+ 'longname' => "Gambier Time",
+ 'shortname' => 'GAMT',
+ 'hasdst' => FALSE ),
+ 'SystemV/YST9' => array(
+ 'offset' => -32400000,
+ 'longname' => "Gambier Time",
+ 'shortname' => 'GAMT',
+ 'hasdst' => FALSE ),
+ 'SystemV/YST9YDT' => array(
+ 'offset' => -32400000,
+ 'longname' => "Alaska Standard Time",
+ 'shortname' => 'AKST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Alaska Daylight Time",
+ 'dstshortname' => 'AKDT' ),
+ 'US/Alaska' => array(
+ 'offset' => -32400000,
+ 'longname' => "Alaska Standard Time",
+ 'shortname' => 'AKST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Alaska Daylight Time",
+ 'dstshortname' => 'AKDT' ),
+ 'America/Dawson' => array(
+ 'offset' => -28800000,
+ 'longname' => "Pacific Standard Time",
+ 'shortname' => 'PST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Pacific Daylight Time",
+ 'dstshortname' => 'PDT' ),
+ 'America/Ensenada' => array(
+ 'offset' => -28800000,
+ 'longname' => "Pacific Standard Time",
+ 'shortname' => 'PST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Pacific Daylight Time",
+ 'dstshortname' => 'PDT' ),
+ 'America/Los_Angeles' => array(
+ 'offset' => -28800000,
+ 'longname' => "Pacific Standard Time",
+ 'shortname' => 'PST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Pacific Daylight Time",
+ 'dstshortname' => 'PDT' ),
+ 'America/Tijuana' => array(
+ 'offset' => -28800000,
+ 'longname' => "Pacific Standard Time",
+ 'shortname' => 'PST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Pacific Daylight Time",
+ 'dstshortname' => 'PDT' ),
+ 'America/Vancouver' => array(
+ 'offset' => -28800000,
+ 'longname' => "Pacific Standard Time",
+ 'shortname' => 'PST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Pacific Daylight Time",
+ 'dstshortname' => 'PDT' ),
+ 'America/Whitehorse' => array(
+ 'offset' => -28800000,
+ 'longname' => "Pacific Standard Time",
+ 'shortname' => 'PST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Pacific Daylight Time",
+ 'dstshortname' => 'PDT' ),
+ 'Canada/Pacific' => array(
+ 'offset' => -28800000,
+ 'longname' => "Pacific Standard Time",
+ 'shortname' => 'PST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Pacific Daylight Time",
+ 'dstshortname' => 'PDT' ),
+ 'Canada/Yukon' => array(
+ 'offset' => -28800000,
+ 'longname' => "Pacific Standard Time",
+ 'shortname' => 'PST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Pacific Daylight Time",
+ 'dstshortname' => 'PDT' ),
+ 'Etc/GMT+8' => array(
+ 'offset' => -28800000,
+ 'longname' => "GMT-08:00",
+ 'shortname' => 'GMT-08:00',
+ 'hasdst' => FALSE ),
+ 'Mexico/BajaNorte' => array(
+ 'offset' => -28800000,
+ 'longname' => "Pacific Standard Time",
+ 'shortname' => 'PST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Pacific Daylight Time",
+ 'dstshortname' => 'PDT' ),
+ 'PST' => array(
+ 'offset' => -28800000,
+ 'longname' => "Pacific Standard Time",
+ 'shortname' => 'PST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Pacific Daylight Time",
+ 'dstshortname' => 'PDT' ),
+ 'PST8PDT' => array(
+ 'offset' => -28800000,
+ 'longname' => "Pacific Standard Time",
+ 'shortname' => 'PST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Pacific Daylight Time",
+ 'dstshortname' => 'PDT' ),
+ 'Pacific/Pitcairn' => array(
+ 'offset' => -28800000,
+ 'longname' => "Pitcairn Standard Time",
+ 'shortname' => 'PST',
+ 'hasdst' => FALSE ),
+ 'SystemV/PST8' => array(
+ 'offset' => -28800000,
+ 'longname' => "Pitcairn Standard Time",
+ 'shortname' => 'PST',
+ 'hasdst' => FALSE ),
+ 'SystemV/PST8PDT' => array(
+ 'offset' => -28800000,
+ 'longname' => "Pacific Standard Time",
+ 'shortname' => 'PST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Pacific Daylight Time",
+ 'dstshortname' => 'PDT' ),
+ 'US/Pacific' => array(
+ 'offset' => -28800000,
+ 'longname' => "Pacific Standard Time",
+ 'shortname' => 'PST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Pacific Daylight Time",
+ 'dstshortname' => 'PDT' ),
+ 'US/Pacific-New' => array(
+ 'offset' => -28800000,
+ 'longname' => "Pacific Standard Time",
+ 'shortname' => 'PST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Pacific Daylight Time",
+ 'dstshortname' => 'PDT' ),
+ 'America/Boise' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Mountain Daylight Time",
+ 'dstshortname' => 'MDT' ),
+ 'America/Cambridge_Bay' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Mountain Daylight Time",
+ 'dstshortname' => 'MDT' ),
+ 'America/Chihuahua' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Mountain Daylight Time",
+ 'dstshortname' => 'MDT' ),
+ 'America/Dawson_Creek' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => FALSE ),
+ 'America/Denver' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Mountain Daylight Time",
+ 'dstshortname' => 'MDT' ),
+ 'America/Edmonton' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Mountain Daylight Time",
+ 'dstshortname' => 'MDT' ),
+ 'America/Hermosillo' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => FALSE ),
+ 'America/Inuvik' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Mountain Daylight Time",
+ 'dstshortname' => 'MDT' ),
+ 'America/Mazatlan' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Mountain Daylight Time",
+ 'dstshortname' => 'MDT' ),
+ 'America/Phoenix' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => FALSE ),
+ 'America/Shiprock' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Mountain Daylight Time",
+ 'dstshortname' => 'MDT' ),
+ 'America/Yellowknife' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Mountain Daylight Time",
+ 'dstshortname' => 'MDT' ),
+ 'Canada/Mountain' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Mountain Daylight Time",
+ 'dstshortname' => 'MDT' ),
+ 'Etc/GMT+7' => array(
+ 'offset' => -25200000,
+ 'longname' => "GMT-07:00",
+ 'shortname' => 'GMT-07:00',
+ 'hasdst' => FALSE ),
+ 'MST' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Mountain Daylight Time",
+ 'dstshortname' => 'MDT' ),
+ 'MST7MDT' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Mountain Daylight Time",
+ 'dstshortname' => 'MDT' ),
+ 'Mexico/BajaSur' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Mountain Daylight Time",
+ 'dstshortname' => 'MDT' ),
+ 'Navajo' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Mountain Daylight Time",
+ 'dstshortname' => 'MDT' ),
+ 'PNT' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => FALSE ),
+ 'SystemV/MST7' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => FALSE ),
+ 'SystemV/MST7MDT' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Mountain Daylight Time",
+ 'dstshortname' => 'MDT' ),
+ 'US/Arizona' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => FALSE ),
+ 'US/Mountain' => array(
+ 'offset' => -25200000,
+ 'longname' => "Mountain Standard Time",
+ 'shortname' => 'MST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Mountain Daylight Time",
+ 'dstshortname' => 'MDT' ),
+ 'America/Belize' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'America/Cancun' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Daylight Time",
+ 'dstshortname' => 'CDT' ),
+ 'America/Chicago' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Daylight Time",
+ 'dstshortname' => 'CDT' ),
+ 'America/Costa_Rica' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'America/El_Salvador' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'America/Guatemala' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'America/Managua' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'America/Menominee' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Daylight Time",
+ 'dstshortname' => 'CDT' ),
+ 'America/Merida' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Daylight Time",
+ 'dstshortname' => 'CDT' ),
+ 'America/Mexico_City' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'America/Monterrey' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Daylight Time",
+ 'dstshortname' => 'CDT' ),
+ 'America/North_Dakota/Center' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Daylight Time",
+ 'dstshortname' => 'CDT' ),
+ 'America/Rainy_River' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Daylight Time",
+ 'dstshortname' => 'CDT' ),
+ 'America/Rankin_Inlet' => array(
+ 'offset' => -21600000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'America/Regina' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'America/Swift_Current' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'America/Tegucigalpa' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'America/Winnipeg' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Daylight Time",
+ 'dstshortname' => 'CDT' ),
+ 'CST' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Daylight Time",
+ 'dstshortname' => 'CDT' ),
+ 'CST6CDT' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Daylight Time",
+ 'dstshortname' => 'CDT' ),
+ 'Canada/Central' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Daylight Time",
+ 'dstshortname' => 'CDT' ),
+ 'Canada/East-Saskatchewan' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'Canada/Saskatchewan' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'Chile/EasterIsland' => array(
+ 'offset' => -21600000,
+ 'longname' => "Easter Is. Time",
+ 'shortname' => 'EAST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Easter Is. Summer Time",
+ 'dstshortname' => 'EASST' ),
+ 'Etc/GMT+6' => array(
+ 'offset' => -21600000,
+ 'longname' => "GMT-06:00",
+ 'shortname' => 'GMT-06:00',
+ 'hasdst' => FALSE ),
+ 'Mexico/General' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'Pacific/Easter' => array(
+ 'offset' => -21600000,
+ 'longname' => "Easter Is. Time",
+ 'shortname' => 'EAST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Easter Is. Summer Time",
+ 'dstshortname' => 'EASST' ),
+ 'Pacific/Galapagos' => array(
+ 'offset' => -21600000,
+ 'longname' => "Galapagos Time",
+ 'shortname' => 'GALT',
+ 'hasdst' => FALSE ),
+ 'SystemV/CST6' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'SystemV/CST6CDT' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Daylight Time",
+ 'dstshortname' => 'CDT' ),
+ 'US/Central' => array(
+ 'offset' => -21600000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Daylight Time",
+ 'dstshortname' => 'CDT' ),
+ 'America/Bogota' => array(
+ 'offset' => -18000000,
+ 'longname' => "Colombia Time",
+ 'shortname' => 'COT',
+ 'hasdst' => FALSE ),
+ 'America/Cayman' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'America/Detroit' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'America/Eirunepe' => array(
+ 'offset' => -18000000,
+ 'longname' => "Acre Time",
+ 'shortname' => 'ACT',
+ 'hasdst' => FALSE ),
+ 'America/Fort_Wayne' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'America/Grand_Turk' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'America/Guayaquil' => array(
+ 'offset' => -18000000,
+ 'longname' => "Ecuador Time",
+ 'shortname' => 'ECT',
+ 'hasdst' => FALSE ),
+ 'America/Havana' => array(
+ 'offset' => -18000000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Daylight Time",
+ 'dstshortname' => 'CDT' ),
+ 'America/Indiana/Indianapolis' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'America/Indiana/Knox' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'America/Indiana/Marengo' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'America/Indiana/Vevay' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'America/Indianapolis' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'America/Iqaluit' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'America/Jamaica' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'America/Kentucky/Louisville' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'America/Kentucky/Monticello' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'America/Knox_IN' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'America/Lima' => array(
+ 'offset' => -18000000,
+ 'longname' => "Peru Time",
+ 'shortname' => 'PET',
+ 'hasdst' => FALSE ),
+ 'America/Louisville' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'America/Montreal' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'America/Nassau' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'America/New_York' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'America/Nipigon' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'America/Panama' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'America/Pangnirtung' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'America/Port-au-Prince' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'America/Porto_Acre' => array(
+ 'offset' => -18000000,
+ 'longname' => "Acre Time",
+ 'shortname' => 'ACT',
+ 'hasdst' => FALSE ),
+ 'America/Rio_Branco' => array(
+ 'offset' => -18000000,
+ 'longname' => "Acre Time",
+ 'shortname' => 'ACT',
+ 'hasdst' => FALSE ),
+ 'America/Thunder_Bay' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'Brazil/Acre' => array(
+ 'offset' => -18000000,
+ 'longname' => "Acre Time",
+ 'shortname' => 'ACT',
+ 'hasdst' => FALSE ),
+ 'Canada/Eastern' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'Cuba' => array(
+ 'offset' => -18000000,
+ 'longname' => "Central Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Daylight Time",
+ 'dstshortname' => 'CDT' ),
+ 'EST' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'EST5EDT' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'Etc/GMT+5' => array(
+ 'offset' => -18000000,
+ 'longname' => "GMT-05:00",
+ 'shortname' => 'GMT-05:00',
+ 'hasdst' => FALSE ),
+ 'IET' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'Jamaica' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'SystemV/EST5' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'SystemV/EST5EDT' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'US/East-Indiana' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'US/Eastern' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'US/Indiana-Starke' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'US/Michigan' => array(
+ 'offset' => -18000000,
+ 'longname' => "Eastern Standard Time",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Daylight Time",
+ 'dstshortname' => 'EDT' ),
+ 'America/Anguilla' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/Antigua' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/Aruba' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/Asuncion' => array(
+ 'offset' => -14400000,
+ 'longname' => "Paraguay Time",
+ 'shortname' => 'PYT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Paraguay Summer Time",
+ 'dstshortname' => 'PYST' ),
+ 'America/Barbados' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/Boa_Vista' => array(
+ 'offset' => -14400000,
+ 'longname' => "Amazon Standard Time",
+ 'shortname' => 'AMT',
+ 'hasdst' => FALSE ),
+ 'America/Caracas' => array(
+ 'offset' => -14400000,
+ 'longname' => "Venezuela Time",
+ 'shortname' => 'VET',
+ 'hasdst' => FALSE ),
+ 'America/Cuiaba' => array(
+ 'offset' => -14400000,
+ 'longname' => "Amazon Standard Time",
+ 'shortname' => 'AMT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Amazon Summer Time",
+ 'dstshortname' => 'AMST' ),
+ 'America/Curacao' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/Dominica' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/Glace_Bay' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Atlantic Daylight Time",
+ 'dstshortname' => 'ADT' ),
+ 'America/Goose_Bay' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Atlantic Daylight Time",
+ 'dstshortname' => 'ADT' ),
+ 'America/Grenada' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/Guadeloupe' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/Guyana' => array(
+ 'offset' => -14400000,
+ 'longname' => "Guyana Time",
+ 'shortname' => 'GYT',
+ 'hasdst' => FALSE ),
+ 'America/Halifax' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Atlantic Daylight Time",
+ 'dstshortname' => 'ADT' ),
+ 'America/La_Paz' => array(
+ 'offset' => -14400000,
+ 'longname' => "Bolivia Time",
+ 'shortname' => 'BOT',
+ 'hasdst' => FALSE ),
+ 'America/Manaus' => array(
+ 'offset' => -14400000,
+ 'longname' => "Amazon Standard Time",
+ 'shortname' => 'AMT',
+ 'hasdst' => FALSE ),
+ 'America/Martinique' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/Montserrat' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/Port_of_Spain' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/Porto_Velho' => array(
+ 'offset' => -14400000,
+ 'longname' => "Amazon Standard Time",
+ 'shortname' => 'AMT',
+ 'hasdst' => FALSE ),
+ 'America/Puerto_Rico' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/Santiago' => array(
+ 'offset' => -14400000,
+ 'longname' => "Chile Time",
+ 'shortname' => 'CLT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Chile Summer Time",
+ 'dstshortname' => 'CLST' ),
+ 'America/Santo_Domingo' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/St_Kitts' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/St_Lucia' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/St_Thomas' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/St_Vincent' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/Thule' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/Tortola' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'America/Virgin' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'Antarctica/Palmer' => array(
+ 'offset' => -14400000,
+ 'longname' => "Chile Time",
+ 'shortname' => 'CLT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Chile Summer Time",
+ 'dstshortname' => 'CLST' ),
+ 'Atlantic/Bermuda' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Atlantic Daylight Time",
+ 'dstshortname' => 'ADT' ),
+ 'Atlantic/Stanley' => array(
+ 'offset' => -14400000,
+ 'longname' => "Falkland Is. Time",
+ 'shortname' => 'FKT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Falkland Is. Summer Time",
+ 'dstshortname' => 'FKST' ),
+ 'Brazil/West' => array(
+ 'offset' => -14400000,
+ 'longname' => "Amazon Standard Time",
+ 'shortname' => 'AMT',
+ 'hasdst' => FALSE ),
+ 'Canada/Atlantic' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Atlantic Daylight Time",
+ 'dstshortname' => 'ADT' ),
+ 'Chile/Continental' => array(
+ 'offset' => -14400000,
+ 'longname' => "Chile Time",
+ 'shortname' => 'CLT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Chile Summer Time",
+ 'dstshortname' => 'CLST' ),
+ 'Etc/GMT+4' => array(
+ 'offset' => -14400000,
+ 'longname' => "GMT-04:00",
+ 'shortname' => 'GMT-04:00',
+ 'hasdst' => FALSE ),
+ 'PRT' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'SystemV/AST4' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'SystemV/AST4ADT' => array(
+ 'offset' => -14400000,
+ 'longname' => "Atlantic Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Atlantic Daylight Time",
+ 'dstshortname' => 'ADT' ),
+ 'America/St_Johns' => array(
+ 'offset' => -12600000,
+ 'longname' => "Newfoundland Standard Time",
+ 'shortname' => 'NST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Newfoundland Daylight Time",
+ 'dstshortname' => 'NDT' ),
+ 'CNT' => array(
+ 'offset' => -12600000,
+ 'longname' => "Newfoundland Standard Time",
+ 'shortname' => 'NST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Newfoundland Daylight Time",
+ 'dstshortname' => 'NDT' ),
+ 'Canada/Newfoundland' => array(
+ 'offset' => -12600000,
+ 'longname' => "Newfoundland Standard Time",
+ 'shortname' => 'NST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Newfoundland Daylight Time",
+ 'dstshortname' => 'NDT' ),
+ 'AGT' => array(
+ 'offset' => -10800000,
+ 'longname' => "Argentine Time",
+ 'shortname' => 'ART',
+ 'hasdst' => FALSE ),
+ 'America/Araguaina' => array(
+ 'offset' => -10800000,
+ 'longname' => "Brazil Time",
+ 'shortname' => 'BRT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Brazil Summer Time",
+ 'dstshortname' => 'BRST' ),
+ 'America/Belem' => array(
+ 'offset' => -10800000,
+ 'longname' => "Brazil Time",
+ 'shortname' => 'BRT',
+ 'hasdst' => FALSE ),
+ 'America/Buenos_Aires' => array(
+ 'offset' => -10800000,
+ 'longname' => "Argentine Time",
+ 'shortname' => 'ART',
+ 'hasdst' => FALSE ),
+ 'America/Catamarca' => array(
+ 'offset' => -10800000,
+ 'longname' => "Argentine Time",
+ 'shortname' => 'ART',
+ 'hasdst' => FALSE ),
+ 'America/Cayenne' => array(
+ 'offset' => -10800000,
+ 'longname' => "French Guiana Time",
+ 'shortname' => 'GFT',
+ 'hasdst' => FALSE ),
+ 'America/Cordoba' => array(
+ 'offset' => -10800000,
+ 'longname' => "Argentine Time",
+ 'shortname' => 'ART',
+ 'hasdst' => FALSE ),
+ 'America/Fortaleza' => array(
+ 'offset' => -10800000,
+ 'longname' => "Brazil Time",
+ 'shortname' => 'BRT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Brazil Summer Time",
+ 'dstshortname' => 'BRST' ),
+ 'America/Godthab' => array(
+ 'offset' => -10800000,
+ 'longname' => "Western Greenland Time",
+ 'shortname' => 'WGT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Western Greenland Summer Time",
+ 'dstshortname' => 'WGST' ),
+ 'America/Jujuy' => array(
+ 'offset' => -10800000,
+ 'longname' => "Argentine Time",
+ 'shortname' => 'ART',
+ 'hasdst' => FALSE ),
+ 'America/Maceio' => array(
+ 'offset' => -10800000,
+ 'longname' => "Brazil Time",
+ 'shortname' => 'BRT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Brazil Summer Time",
+ 'dstshortname' => 'BRST' ),
+ 'America/Mendoza' => array(
+ 'offset' => -10800000,
+ 'longname' => "Argentine Time",
+ 'shortname' => 'ART',
+ 'hasdst' => FALSE ),
+ 'America/Miquelon' => array(
+ 'offset' => -10800000,
+ 'longname' => "Pierre & Miquelon Standard Time",
+ 'shortname' => 'PMST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Pierre & Miquelon Daylight Time",
+ 'dstshortname' => 'PMDT' ),
+ 'America/Montevideo' => array(
+ 'offset' => -10800000,
+ 'longname' => "Uruguay Time",
+ 'shortname' => 'UYT',
+ 'hasdst' => FALSE ),
+ 'America/Paramaribo' => array(
+ 'offset' => -10800000,
+ 'longname' => "Suriname Time",
+ 'shortname' => 'SRT',
+ 'hasdst' => FALSE ),
+ 'America/Recife' => array(
+ 'offset' => -10800000,
+ 'longname' => "Brazil Time",
+ 'shortname' => 'BRT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Brazil Summer Time",
+ 'dstshortname' => 'BRST' ),
+ 'America/Rosario' => array(
+ 'offset' => -10800000,
+ 'longname' => "Argentine Time",
+ 'shortname' => 'ART',
+ 'hasdst' => FALSE ),
+ 'America/Sao_Paulo' => array(
+ 'offset' => -10800000,
+ 'longname' => "Brazil Time",
+ 'shortname' => 'BRT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Brazil Summer Time",
+ 'dstshortname' => 'BRST' ),
+ 'BET' => array(
+ 'offset' => -10800000,
+ 'longname' => "Brazil Time",
+ 'shortname' => 'BRT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Brazil Summer Time",
+ 'dstshortname' => 'BRST' ),
+ 'Brazil/East' => array(
+ 'offset' => -10800000,
+ 'longname' => "Brazil Time",
+ 'shortname' => 'BRT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Brazil Summer Time",
+ 'dstshortname' => 'BRST' ),
+ 'Etc/GMT+3' => array(
+ 'offset' => -10800000,
+ 'longname' => "GMT-03:00",
+ 'shortname' => 'GMT-03:00',
+ 'hasdst' => FALSE ),
+ 'America/Noronha' => array(
+ 'offset' => -7200000,
+ 'longname' => "Fernando de Noronha Time",
+ 'shortname' => 'FNT',
+ 'hasdst' => FALSE ),
+ 'Atlantic/South_Georgia' => array(
+ 'offset' => -7200000,
+ 'longname' => "South Georgia Standard Time",
+ 'shortname' => 'GST',
+ 'hasdst' => FALSE ),
+ 'Brazil/DeNoronha' => array(
+ 'offset' => -7200000,
+ 'longname' => "Fernando de Noronha Time",
+ 'shortname' => 'FNT',
+ 'hasdst' => FALSE ),
+ 'Etc/GMT+2' => array(
+ 'offset' => -7200000,
+ 'longname' => "GMT-02:00",
+ 'shortname' => 'GMT-02:00',
+ 'hasdst' => FALSE ),
+ 'America/Scoresbysund' => array(
+ 'offset' => -3600000,
+ 'longname' => "Eastern Greenland Time",
+ 'shortname' => 'EGT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Greenland Summer Time",
+ 'dstshortname' => 'EGST' ),
+ 'Atlantic/Azores' => array(
+ 'offset' => -3600000,
+ 'longname' => "Azores Time",
+ 'shortname' => 'AZOT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Azores Summer Time",
+ 'dstshortname' => 'AZOST' ),
+ 'Atlantic/Cape_Verde' => array(
+ 'offset' => -3600000,
+ 'longname' => "Cape Verde Time",
+ 'shortname' => 'CVT',
+ 'hasdst' => FALSE ),
+ 'Etc/GMT+1' => array(
+ 'offset' => -3600000,
+ 'longname' => "GMT-01:00",
+ 'shortname' => 'GMT-01:00',
+ 'hasdst' => FALSE ),
+ 'Africa/Abidjan' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Africa/Accra' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Africa/Bamako' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Africa/Banjul' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Africa/Bissau' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Africa/Casablanca' => array(
+ 'offset' => 0,
+ 'longname' => "Western European Time",
+ 'shortname' => 'WET',
+ 'hasdst' => FALSE ),
+ 'Africa/Conakry' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Africa/Dakar' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Africa/El_Aaiun' => array(
+ 'offset' => 0,
+ 'longname' => "Western European Time",
+ 'shortname' => 'WET',
+ 'hasdst' => FALSE ),
+ 'Africa/Freetown' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Africa/Lome' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Africa/Monrovia' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Africa/Nouakchott' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Africa/Ouagadougou' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Africa/Sao_Tome' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Africa/Timbuktu' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'America/Danmarkshavn' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Atlantic/Canary' => array(
+ 'offset' => 0,
+ 'longname' => "Western European Time",
+ 'shortname' => 'WET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Western European Summer Time",
+ 'dstshortname' => 'WEST' ),
+ 'Atlantic/Faeroe' => array(
+ 'offset' => 0,
+ 'longname' => "Western European Time",
+ 'shortname' => 'WET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Western European Summer Time",
+ 'dstshortname' => 'WEST' ),
+ 'Atlantic/Madeira' => array(
+ 'offset' => 0,
+ 'longname' => "Western European Time",
+ 'shortname' => 'WET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Western European Summer Time",
+ 'dstshortname' => 'WEST' ),
+ 'Atlantic/Reykjavik' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Atlantic/St_Helena' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Eire' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Irish Summer Time",
+ 'dstshortname' => 'IST' ),
+ 'Etc/GMT' => array(
+ 'offset' => 0,
+ 'longname' => "GMT+00:00",
+ 'shortname' => 'GMT+00:00',
+ 'hasdst' => FALSE ),
+ 'Etc/GMT+0' => array(
+ 'offset' => 0,
+ 'longname' => "GMT+00:00",
+ 'shortname' => 'GMT+00:00',
+ 'hasdst' => FALSE ),
+ 'Etc/GMT-0' => array(
+ 'offset' => 0,
+ 'longname' => "GMT+00:00",
+ 'shortname' => 'GMT+00:00',
+ 'hasdst' => FALSE ),
+ 'Etc/GMT0' => array(
+ 'offset' => 0,
+ 'longname' => "GMT+00:00",
+ 'shortname' => 'GMT+00:00',
+ 'hasdst' => FALSE ),
+ 'Etc/Greenwich' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Etc/UCT' => array(
+ 'offset' => 0,
+ 'longname' => "Coordinated Universal Time",
+ 'shortname' => 'UTC',
+ 'hasdst' => FALSE ),
+ 'Etc/UTC' => array(
+ 'offset' => 0,
+ 'longname' => "Coordinated Universal Time",
+ 'shortname' => 'UTC',
+ 'hasdst' => FALSE ),
+ 'Etc/Universal' => array(
+ 'offset' => 0,
+ 'longname' => "Coordinated Universal Time",
+ 'shortname' => 'UTC',
+ 'hasdst' => FALSE ),
+ 'Etc/Zulu' => array(
+ 'offset' => 0,
+ 'longname' => "Coordinated Universal Time",
+ 'shortname' => 'UTC',
+ 'hasdst' => FALSE ),
+ 'Europe/Belfast' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "British Summer Time",
+ 'dstshortname' => 'BST' ),
+ 'Europe/Dublin' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Irish Summer Time",
+ 'dstshortname' => 'IST' ),
+ 'Europe/Lisbon' => array(
+ 'offset' => 0,
+ 'longname' => "Western European Time",
+ 'shortname' => 'WET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Western European Summer Time",
+ 'dstshortname' => 'WEST' ),
+ 'Europe/London' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "British Summer Time",
+ 'dstshortname' => 'BST' ),
+ 'GB' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "British Summer Time",
+ 'dstshortname' => 'BST' ),
+ 'GB-Eire' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "British Summer Time",
+ 'dstshortname' => 'BST' ),
+ 'GMT' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'GMT0' => array(
+ 'offset' => 0,
+ 'longname' => "GMT+00:00",
+ 'shortname' => 'GMT+00:00',
+ 'hasdst' => FALSE ),
+ 'Greenwich' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Iceland' => array(
+ 'offset' => 0,
+ 'longname' => "Greenwich Mean Time",
+ 'shortname' => 'GMT',
+ 'hasdst' => FALSE ),
+ 'Portugal' => array(
+ 'offset' => 0,
+ 'longname' => "Western European Time",
+ 'shortname' => 'WET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Western European Summer Time",
+ 'dstshortname' => 'WEST' ),
+ 'UCT' => array(
+ 'offset' => 0,
+ 'longname' => "Coordinated Universal Time",
+ 'shortname' => 'UTC',
+ 'hasdst' => FALSE ),
+ 'UTC' => array(
+ 'offset' => 0,
+ 'longname' => "Coordinated Universal Time",
+ 'shortname' => 'UTC',
+ 'hasdst' => FALSE ),
+ 'Universal' => array(
+ 'offset' => 0,
+ 'longname' => "Coordinated Universal Time",
+ 'shortname' => 'UTC',
+ 'hasdst' => FALSE ),
+ 'WET' => array(
+ 'offset' => 0,
+ 'longname' => "Western European Time",
+ 'shortname' => 'WET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Western European Summer Time",
+ 'dstshortname' => 'WEST' ),
+ 'Zulu' => array(
+ 'offset' => 0,
+ 'longname' => "Coordinated Universal Time",
+ 'shortname' => 'UTC',
+ 'hasdst' => FALSE ),
+ 'Africa/Algiers' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => FALSE ),
+ 'Africa/Bangui' => array(
+ 'offset' => 3600000,
+ 'longname' => "Western African Time",
+ 'shortname' => 'WAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Brazzaville' => array(
+ 'offset' => 3600000,
+ 'longname' => "Western African Time",
+ 'shortname' => 'WAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Ceuta' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Africa/Douala' => array(
+ 'offset' => 3600000,
+ 'longname' => "Western African Time",
+ 'shortname' => 'WAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Kinshasa' => array(
+ 'offset' => 3600000,
+ 'longname' => "Western African Time",
+ 'shortname' => 'WAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Lagos' => array(
+ 'offset' => 3600000,
+ 'longname' => "Western African Time",
+ 'shortname' => 'WAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Libreville' => array(
+ 'offset' => 3600000,
+ 'longname' => "Western African Time",
+ 'shortname' => 'WAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Luanda' => array(
+ 'offset' => 3600000,
+ 'longname' => "Western African Time",
+ 'shortname' => 'WAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Malabo' => array(
+ 'offset' => 3600000,
+ 'longname' => "Western African Time",
+ 'shortname' => 'WAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Ndjamena' => array(
+ 'offset' => 3600000,
+ 'longname' => "Western African Time",
+ 'shortname' => 'WAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Niamey' => array(
+ 'offset' => 3600000,
+ 'longname' => "Western African Time",
+ 'shortname' => 'WAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Porto-Novo' => array(
+ 'offset' => 3600000,
+ 'longname' => "Western African Time",
+ 'shortname' => 'WAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Tunis' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => FALSE ),
+ 'Africa/Windhoek' => array(
+ 'offset' => 3600000,
+ 'longname' => "Western African Time",
+ 'shortname' => 'WAT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Western African Summer Time",
+ 'dstshortname' => 'WAST' ),
+ 'Arctic/Longyearbyen' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Atlantic/Jan_Mayen' => array(
+ 'offset' => 3600000,
+ 'longname' => "Eastern Greenland Time",
+ 'shortname' => 'EGT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Greenland Summer Time",
+ 'dstshortname' => 'EGST' ),
+ 'CET' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'ECT' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Etc/GMT-1' => array(
+ 'offset' => 3600000,
+ 'longname' => "GMT+01:00",
+ 'shortname' => 'GMT+01:00',
+ 'hasdst' => FALSE ),
+ 'Europe/Amsterdam' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Andorra' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Belgrade' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Berlin' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Bratislava' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Brussels' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Budapest' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Copenhagen' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Gibraltar' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Ljubljana' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Luxembourg' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Madrid' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Malta' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Monaco' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Oslo' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Paris' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Prague' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Rome' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/San_Marino' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Sarajevo' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Skopje' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Stockholm' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Tirane' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Vaduz' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Vatican' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Vienna' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Warsaw' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Zagreb' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'Europe/Zurich' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'MET' => array(
+ 'offset' => 3600000,
+ 'longname' => "Middle Europe Time",
+ 'shortname' => 'MET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Middle Europe Summer Time",
+ 'dstshortname' => 'MEST' ),
+ 'Poland' => array(
+ 'offset' => 3600000,
+ 'longname' => "Central European Time",
+ 'shortname' => 'CET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central European Summer Time",
+ 'dstshortname' => 'CEST' ),
+ 'ART' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Africa/Blantyre' => array(
+ 'offset' => 7200000,
+ 'longname' => "Central African Time",
+ 'shortname' => 'CAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Bujumbura' => array(
+ 'offset' => 7200000,
+ 'longname' => "Central African Time",
+ 'shortname' => 'CAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Cairo' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Africa/Gaborone' => array(
+ 'offset' => 7200000,
+ 'longname' => "Central African Time",
+ 'shortname' => 'CAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Harare' => array(
+ 'offset' => 7200000,
+ 'longname' => "Central African Time",
+ 'shortname' => 'CAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Johannesburg' => array(
+ 'offset' => 7200000,
+ 'longname' => "South Africa Standard Time",
+ 'shortname' => 'SAST',
+ 'hasdst' => FALSE ),
+ 'Africa/Kigali' => array(
+ 'offset' => 7200000,
+ 'longname' => "Central African Time",
+ 'shortname' => 'CAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Lubumbashi' => array(
+ 'offset' => 7200000,
+ 'longname' => "Central African Time",
+ 'shortname' => 'CAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Lusaka' => array(
+ 'offset' => 7200000,
+ 'longname' => "Central African Time",
+ 'shortname' => 'CAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Maputo' => array(
+ 'offset' => 7200000,
+ 'longname' => "Central African Time",
+ 'shortname' => 'CAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Maseru' => array(
+ 'offset' => 7200000,
+ 'longname' => "South Africa Standard Time",
+ 'shortname' => 'SAST',
+ 'hasdst' => FALSE ),
+ 'Africa/Mbabane' => array(
+ 'offset' => 7200000,
+ 'longname' => "South Africa Standard Time",
+ 'shortname' => 'SAST',
+ 'hasdst' => FALSE ),
+ 'Africa/Tripoli' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => FALSE ),
+ 'Asia/Amman' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Asia/Beirut' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Asia/Damascus' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Asia/Gaza' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Asia/Istanbul' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Asia/Jerusalem' => array(
+ 'offset' => 7200000,
+ 'longname' => "Israel Standard Time",
+ 'shortname' => 'IST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Israel Daylight Time",
+ 'dstshortname' => 'IDT' ),
+ 'Asia/Nicosia' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Asia/Tel_Aviv' => array(
+ 'offset' => 7200000,
+ 'longname' => "Israel Standard Time",
+ 'shortname' => 'IST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Israel Daylight Time",
+ 'dstshortname' => 'IDT' ),
+ 'CAT' => array(
+ 'offset' => 7200000,
+ 'longname' => "Central African Time",
+ 'shortname' => 'CAT',
+ 'hasdst' => FALSE ),
+ 'EET' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Egypt' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Etc/GMT-2' => array(
+ 'offset' => 7200000,
+ 'longname' => "GMT+02:00",
+ 'shortname' => 'GMT+02:00',
+ 'hasdst' => FALSE ),
+ 'Europe/Athens' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Europe/Bucharest' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Europe/Chisinau' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Europe/Helsinki' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Europe/Istanbul' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Europe/Kaliningrad' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Europe/Kiev' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Europe/Minsk' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Europe/Nicosia' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Europe/Riga' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Europe/Simferopol' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Europe/Sofia' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Europe/Tallinn' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => FALSE ),
+ 'Europe/Tiraspol' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Europe/Uzhgorod' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Europe/Vilnius' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => FALSE ),
+ 'Europe/Zaporozhye' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Israel' => array(
+ 'offset' => 7200000,
+ 'longname' => "Israel Standard Time",
+ 'shortname' => 'IST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Israel Daylight Time",
+ 'dstshortname' => 'IDT' ),
+ 'Libya' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => FALSE ),
+ 'Turkey' => array(
+ 'offset' => 7200000,
+ 'longname' => "Eastern European Time",
+ 'shortname' => 'EET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern European Summer Time",
+ 'dstshortname' => 'EEST' ),
+ 'Africa/Addis_Ababa' => array(
+ 'offset' => 10800000,
+ 'longname' => "Eastern African Time",
+ 'shortname' => 'EAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Asmera' => array(
+ 'offset' => 10800000,
+ 'longname' => "Eastern African Time",
+ 'shortname' => 'EAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Dar_es_Salaam' => array(
+ 'offset' => 10800000,
+ 'longname' => "Eastern African Time",
+ 'shortname' => 'EAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Djibouti' => array(
+ 'offset' => 10800000,
+ 'longname' => "Eastern African Time",
+ 'shortname' => 'EAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Kampala' => array(
+ 'offset' => 10800000,
+ 'longname' => "Eastern African Time",
+ 'shortname' => 'EAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Khartoum' => array(
+ 'offset' => 10800000,
+ 'longname' => "Eastern African Time",
+ 'shortname' => 'EAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Mogadishu' => array(
+ 'offset' => 10800000,
+ 'longname' => "Eastern African Time",
+ 'shortname' => 'EAT',
+ 'hasdst' => FALSE ),
+ 'Africa/Nairobi' => array(
+ 'offset' => 10800000,
+ 'longname' => "Eastern African Time",
+ 'shortname' => 'EAT',
+ 'hasdst' => FALSE ),
+ 'Antarctica/Syowa' => array(
+ 'offset' => 10800000,
+ 'longname' => "Syowa Time",
+ 'shortname' => 'SYOT',
+ 'hasdst' => FALSE ),
+ 'Asia/Aden' => array(
+ 'offset' => 10800000,
+ 'longname' => "Arabia Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'Asia/Baghdad' => array(
+ 'offset' => 10800000,
+ 'longname' => "Arabia Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Arabia Daylight Time",
+ 'dstshortname' => 'ADT' ),
+ 'Asia/Bahrain' => array(
+ 'offset' => 10800000,
+ 'longname' => "Arabia Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'Asia/Kuwait' => array(
+ 'offset' => 10800000,
+ 'longname' => "Arabia Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'Asia/Qatar' => array(
+ 'offset' => 10800000,
+ 'longname' => "Arabia Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'Asia/Riyadh' => array(
+ 'offset' => 10800000,
+ 'longname' => "Arabia Standard Time",
+ 'shortname' => 'AST',
+ 'hasdst' => FALSE ),
+ 'EAT' => array(
+ 'offset' => 10800000,
+ 'longname' => "Eastern African Time",
+ 'shortname' => 'EAT',
+ 'hasdst' => FALSE ),
+ 'Etc/GMT-3' => array(
+ 'offset' => 10800000,
+ 'longname' => "GMT+03:00",
+ 'shortname' => 'GMT+03:00',
+ 'hasdst' => FALSE ),
+ 'Europe/Moscow' => array(
+ 'offset' => 10800000,
+ 'longname' => "Moscow Standard Time",
+ 'shortname' => 'MSK',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Moscow Daylight Time",
+ 'dstshortname' => 'MSD' ),
+ 'Indian/Antananarivo' => array(
+ 'offset' => 10800000,
+ 'longname' => "Eastern African Time",
+ 'shortname' => 'EAT',
+ 'hasdst' => FALSE ),
+ 'Indian/Comoro' => array(
+ 'offset' => 10800000,
+ 'longname' => "Eastern African Time",
+ 'shortname' => 'EAT',
+ 'hasdst' => FALSE ),
+ 'Indian/Mayotte' => array(
+ 'offset' => 10800000,
+ 'longname' => "Eastern African Time",
+ 'shortname' => 'EAT',
+ 'hasdst' => FALSE ),
+ 'W-SU' => array(
+ 'offset' => 10800000,
+ 'longname' => "Moscow Standard Time",
+ 'shortname' => 'MSK',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Moscow Daylight Time",
+ 'dstshortname' => 'MSD' ),
+ 'Asia/Riyadh87' => array(
+ 'offset' => 11224000,
+ 'longname' => "GMT+03:07",
+ 'shortname' => 'GMT+03:07',
+ 'hasdst' => FALSE ),
+ 'Asia/Riyadh88' => array(
+ 'offset' => 11224000,
+ 'longname' => "GMT+03:07",
+ 'shortname' => 'GMT+03:07',
+ 'hasdst' => FALSE ),
+ 'Asia/Riyadh89' => array(
+ 'offset' => 11224000,
+ 'longname' => "GMT+03:07",
+ 'shortname' => 'GMT+03:07',
+ 'hasdst' => FALSE ),
+ 'Mideast/Riyadh87' => array(
+ 'offset' => 11224000,
+ 'longname' => "GMT+03:07",
+ 'shortname' => 'GMT+03:07',
+ 'hasdst' => FALSE ),
+ 'Mideast/Riyadh88' => array(
+ 'offset' => 11224000,
+ 'longname' => "GMT+03:07",
+ 'shortname' => 'GMT+03:07',
+ 'hasdst' => FALSE ),
+ 'Mideast/Riyadh89' => array(
+ 'offset' => 11224000,
+ 'longname' => "GMT+03:07",
+ 'shortname' => 'GMT+03:07',
+ 'hasdst' => FALSE ),
+ 'Asia/Tehran' => array(
+ 'offset' => 12600000,
+ 'longname' => "Iran Time",
+ 'shortname' => 'IRT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Iran Sumer Time",
+ 'dstshortname' => 'IRST' ),
+ 'Iran' => array(
+ 'offset' => 12600000,
+ 'longname' => "Iran Time",
+ 'shortname' => 'IRT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Iran Sumer Time",
+ 'dstshortname' => 'IRST' ),
+ 'Asia/Aqtau' => array(
+ 'offset' => 14400000,
+ 'longname' => "Aqtau Time",
+ 'shortname' => 'AQTT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Aqtau Summer Time",
+ 'dstshortname' => 'AQTST' ),
+ 'Asia/Baku' => array(
+ 'offset' => 14400000,
+ 'longname' => "Azerbaijan Time",
+ 'shortname' => 'AZT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Azerbaijan Summer Time",
+ 'dstshortname' => 'AZST' ),
+ 'Asia/Dubai' => array(
+ 'offset' => 14400000,
+ 'longname' => "Gulf Standard Time",
+ 'shortname' => 'GST',
+ 'hasdst' => FALSE ),
+ 'Asia/Muscat' => array(
+ 'offset' => 14400000,
+ 'longname' => "Gulf Standard Time",
+ 'shortname' => 'GST',
+ 'hasdst' => FALSE ),
+ 'Asia/Tbilisi' => array(
+ 'offset' => 14400000,
+ 'longname' => "Georgia Time",
+ 'shortname' => 'GET',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Georgia Summer Time",
+ 'dstshortname' => 'GEST' ),
+ 'Asia/Yerevan' => array(
+ 'offset' => 14400000,
+ 'longname' => "Armenia Time",
+ 'shortname' => 'AMT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Armenia Summer Time",
+ 'dstshortname' => 'AMST' ),
+ 'Etc/GMT-4' => array(
+ 'offset' => 14400000,
+ 'longname' => "GMT+04:00",
+ 'shortname' => 'GMT+04:00',
+ 'hasdst' => FALSE ),
+ 'Europe/Samara' => array(
+ 'offset' => 14400000,
+ 'longname' => "Samara Time",
+ 'shortname' => 'SAMT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Samara Summer Time",
+ 'dstshortname' => 'SAMST' ),
+ 'Indian/Mahe' => array(
+ 'offset' => 14400000,
+ 'longname' => "Seychelles Time",
+ 'shortname' => 'SCT',
+ 'hasdst' => FALSE ),
+ 'Indian/Mauritius' => array(
+ 'offset' => 14400000,
+ 'longname' => "Mauritius Time",
+ 'shortname' => 'MUT',
+ 'hasdst' => FALSE ),
+ 'Indian/Reunion' => array(
+ 'offset' => 14400000,
+ 'longname' => "Reunion Time",
+ 'shortname' => 'RET',
+ 'hasdst' => FALSE ),
+ 'NET' => array(
+ 'offset' => 14400000,
+ 'longname' => "Armenia Time",
+ 'shortname' => 'AMT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Armenia Summer Time",
+ 'dstshortname' => 'AMST' ),
+ 'Asia/Kabul' => array(
+ 'offset' => 16200000,
+ 'longname' => "Afghanistan Time",
+ 'shortname' => 'AFT',
+ 'hasdst' => FALSE ),
+ 'Asia/Aqtobe' => array(
+ 'offset' => 18000000,
+ 'longname' => "Aqtobe Time",
+ 'shortname' => 'AQTT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Aqtobe Summer Time",
+ 'dstshortname' => 'AQTST' ),
+ 'Asia/Ashgabat' => array(
+ 'offset' => 18000000,
+ 'longname' => "Turkmenistan Time",
+ 'shortname' => 'TMT',
+ 'hasdst' => FALSE ),
+ 'Asia/Ashkhabad' => array(
+ 'offset' => 18000000,
+ 'longname' => "Turkmenistan Time",
+ 'shortname' => 'TMT',
+ 'hasdst' => FALSE ),
+ 'Asia/Bishkek' => array(
+ 'offset' => 18000000,
+ 'longname' => "Kirgizstan Time",
+ 'shortname' => 'KGT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Kirgizstan Summer Time",
+ 'dstshortname' => 'KGST' ),
+ 'Asia/Dushanbe' => array(
+ 'offset' => 18000000,
+ 'longname' => "Tajikistan Time",
+ 'shortname' => 'TJT',
+ 'hasdst' => FALSE ),
+ 'Asia/Karachi' => array(
+ 'offset' => 18000000,
+ 'longname' => "Pakistan Time",
+ 'shortname' => 'PKT',
+ 'hasdst' => FALSE ),
+ 'Asia/Samarkand' => array(
+ 'offset' => 18000000,
+ 'longname' => "Turkmenistan Time",
+ 'shortname' => 'TMT',
+ 'hasdst' => FALSE ),
+ 'Asia/Tashkent' => array(
+ 'offset' => 18000000,
+ 'longname' => "Uzbekistan Time",
+ 'shortname' => 'UZT',
+ 'hasdst' => FALSE ),
+ 'Asia/Yekaterinburg' => array(
+ 'offset' => 18000000,
+ 'longname' => "Yekaterinburg Time",
+ 'shortname' => 'YEKT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Yekaterinburg Summer Time",
+ 'dstshortname' => 'YEKST' ),
+ 'Etc/GMT-5' => array(
+ 'offset' => 18000000,
+ 'longname' => "GMT+05:00",
+ 'shortname' => 'GMT+05:00',
+ 'hasdst' => FALSE ),
+ 'Indian/Kerguelen' => array(
+ 'offset' => 18000000,
+ 'longname' => "French Southern & Antarctic Lands Time",
+ 'shortname' => 'TFT',
+ 'hasdst' => FALSE ),
+ 'Indian/Maldives' => array(
+ 'offset' => 18000000,
+ 'longname' => "Maldives Time",
+ 'shortname' => 'MVT',
+ 'hasdst' => FALSE ),
+ 'PLT' => array(
+ 'offset' => 18000000,
+ 'longname' => "Pakistan Time",
+ 'shortname' => 'PKT',
+ 'hasdst' => FALSE ),
+ 'Asia/Calcutta' => array(
+ 'offset' => 19800000,
+ 'longname' => "India Standard Time",
+ 'shortname' => 'IST',
+ 'hasdst' => FALSE ),
+ 'IST' => array(
+ 'offset' => 19800000,
+ 'longname' => "India Standard Time",
+ 'shortname' => 'IST',
+ 'hasdst' => FALSE ),
+ 'Asia/Katmandu' => array(
+ 'offset' => 20700000,
+ 'longname' => "Nepal Time",
+ 'shortname' => 'NPT',
+ 'hasdst' => FALSE ),
+ 'Antarctica/Mawson' => array(
+ 'offset' => 21600000,
+ 'longname' => "Mawson Time",
+ 'shortname' => 'MAWT',
+ 'hasdst' => FALSE ),
+ 'Antarctica/Vostok' => array(
+ 'offset' => 21600000,
+ 'longname' => "Vostok time",
+ 'shortname' => 'VOST',
+ 'hasdst' => FALSE ),
+ 'Asia/Almaty' => array(
+ 'offset' => 21600000,
+ 'longname' => "Alma-Ata Time",
+ 'shortname' => 'ALMT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Alma-Ata Summer Time",
+ 'dstshortname' => 'ALMST' ),
+ 'Asia/Colombo' => array(
+ 'offset' => 21600000,
+ 'longname' => "Sri Lanka Time",
+ 'shortname' => 'LKT',
+ 'hasdst' => FALSE ),
+ 'Asia/Dacca' => array(
+ 'offset' => 21600000,
+ 'longname' => "Bangladesh Time",
+ 'shortname' => 'BDT',
+ 'hasdst' => FALSE ),
+ 'Asia/Dhaka' => array(
+ 'offset' => 21600000,
+ 'longname' => "Bangladesh Time",
+ 'shortname' => 'BDT',
+ 'hasdst' => FALSE ),
+ 'Asia/Novosibirsk' => array(
+ 'offset' => 21600000,
+ 'longname' => "Novosibirsk Time",
+ 'shortname' => 'NOVT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Novosibirsk Summer Time",
+ 'dstshortname' => 'NOVST' ),
+ 'Asia/Omsk' => array(
+ 'offset' => 21600000,
+ 'longname' => "Omsk Time",
+ 'shortname' => 'OMST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Omsk Summer Time",
+ 'dstshortname' => 'OMSST' ),
+ 'Asia/Thimbu' => array(
+ 'offset' => 21600000,
+ 'longname' => "Bhutan Time",
+ 'shortname' => 'BTT',
+ 'hasdst' => FALSE ),
+ 'Asia/Thimphu' => array(
+ 'offset' => 21600000,
+ 'longname' => "Bhutan Time",
+ 'shortname' => 'BTT',
+ 'hasdst' => FALSE ),
+ 'BDT' => array(
+ 'offset' => 21600000,
+ 'longname' => "Bangladesh Time",
+ 'shortname' => 'BDT',
+ 'hasdst' => TRUE ),
+ 'Etc/GMT-6' => array(
+ 'offset' => 21600000,
+ 'longname' => "GMT+06:00",
+ 'shortname' => 'GMT+06:00',
+ 'hasdst' => FALSE ),
+ 'Indian/Chagos' => array(
+ 'offset' => 21600000,
+ 'longname' => "Indian Ocean Territory Time",
+ 'shortname' => 'IOT',
+ 'hasdst' => FALSE ),
+ 'Asia/Rangoon' => array(
+ 'offset' => 23400000,
+ 'longname' => "Myanmar Time",
+ 'shortname' => 'MMT',
+ 'hasdst' => FALSE ),
+ 'Indian/Cocos' => array(
+ 'offset' => 23400000,
+ 'longname' => "Cocos Islands Time",
+ 'shortname' => 'CCT',
+ 'hasdst' => FALSE ),
+ 'Antarctica/Davis' => array(
+ 'offset' => 25200000,
+ 'longname' => "Davis Time",
+ 'shortname' => 'DAVT',
+ 'hasdst' => FALSE ),
+ 'Asia/Bangkok' => array(
+ 'offset' => 25200000,
+ 'longname' => "Indochina Time",
+ 'shortname' => 'ICT',
+ 'hasdst' => FALSE ),
+ 'Asia/Hovd' => array(
+ 'offset' => 25200000,
+ 'longname' => "Hovd Time",
+ 'shortname' => 'HOVT',
+ 'hasdst' => FALSE ),
+ 'Asia/Jakarta' => array(
+ 'offset' => 25200000,
+ 'longname' => "West Indonesia Time",
+ 'shortname' => 'WIT',
+ 'hasdst' => FALSE ),
+ 'Asia/Krasnoyarsk' => array(
+ 'offset' => 25200000,
+ 'longname' => "Krasnoyarsk Time",
+ 'shortname' => 'KRAT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Krasnoyarsk Summer Time",
+ 'dstshortname' => 'KRAST' ),
+ 'Asia/Phnom_Penh' => array(
+ 'offset' => 25200000,
+ 'longname' => "Indochina Time",
+ 'shortname' => 'ICT',
+ 'hasdst' => FALSE ),
+ 'Asia/Pontianak' => array(
+ 'offset' => 25200000,
+ 'longname' => "West Indonesia Time",
+ 'shortname' => 'WIT',
+ 'hasdst' => FALSE ),
+ 'Asia/Saigon' => array(
+ 'offset' => 25200000,
+ 'longname' => "Indochina Time",
+ 'shortname' => 'ICT',
+ 'hasdst' => FALSE ),
+ 'Asia/Vientiane' => array(
+ 'offset' => 25200000,
+ 'longname' => "Indochina Time",
+ 'shortname' => 'ICT',
+ 'hasdst' => FALSE ),
+ 'Etc/GMT-7' => array(
+ 'offset' => 25200000,
+ 'longname' => "GMT+07:00",
+ 'shortname' => 'GMT+07:00',
+ 'hasdst' => FALSE ),
+ 'Indian/Christmas' => array(
+ 'offset' => 25200000,
+ 'longname' => "Christmas Island Time",
+ 'shortname' => 'CXT',
+ 'hasdst' => FALSE ),
+ 'VST' => array(
+ 'offset' => 25200000,
+ 'longname' => "Indochina Time",
+ 'shortname' => 'ICT',
+ 'hasdst' => FALSE ),
+ 'Antarctica/Casey' => array(
+ 'offset' => 28800000,
+ 'longname' => "Western Standard Time (Australia)",
+ 'shortname' => 'WST',
+ 'hasdst' => FALSE ),
+ 'Asia/Brunei' => array(
+ 'offset' => 28800000,
+ 'longname' => "Brunei Time",
+ 'shortname' => 'BNT',
+ 'hasdst' => FALSE ),
+ 'Asia/Chongqing' => array(
+ 'offset' => 28800000,
+ 'longname' => "China Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'Asia/Chungking' => array(
+ 'offset' => 28800000,
+ 'longname' => "China Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'Asia/Harbin' => array(
+ 'offset' => 28800000,
+ 'longname' => "China Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'Asia/Hong_Kong' => array(
+ 'offset' => 28800000,
+ 'longname' => "Hong Kong Time",
+ 'shortname' => 'HKT',
+ 'hasdst' => FALSE ),
+ 'Asia/Irkutsk' => array(
+ 'offset' => 28800000,
+ 'longname' => "Irkutsk Time",
+ 'shortname' => 'IRKT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Irkutsk Summer Time",
+ 'dstshortname' => 'IRKST' ),
+ 'Asia/Kashgar' => array(
+ 'offset' => 28800000,
+ 'longname' => "China Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'Asia/Kuala_Lumpur' => array(
+ 'offset' => 28800000,
+ 'longname' => "Malaysia Time",
+ 'shortname' => 'MYT',
+ 'hasdst' => FALSE ),
+ 'Asia/Kuching' => array(
+ 'offset' => 28800000,
+ 'longname' => "Malaysia Time",
+ 'shortname' => 'MYT',
+ 'hasdst' => FALSE ),
+ 'Asia/Macao' => array(
+ 'offset' => 28800000,
+ 'longname' => "China Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'Asia/Manila' => array(
+ 'offset' => 28800000,
+ 'longname' => "Philippines Time",
+ 'shortname' => 'PHT',
+ 'hasdst' => FALSE ),
+ 'Asia/Shanghai' => array(
+ 'offset' => 28800000,
+ 'longname' => "China Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'Asia/Singapore' => array(
+ 'offset' => 28800000,
+ 'longname' => "Singapore Time",
+ 'shortname' => 'SGT',
+ 'hasdst' => FALSE ),
+ 'Asia/Taipei' => array(
+ 'offset' => 28800000,
+ 'longname' => "China Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'Asia/Ujung_Pandang' => array(
+ 'offset' => 28800000,
+ 'longname' => "Central Indonesia Time",
+ 'shortname' => 'CIT',
+ 'hasdst' => FALSE ),
+ 'Asia/Ulaanbaatar' => array(
+ 'offset' => 28800000,
+ 'longname' => "Ulaanbaatar Time",
+ 'shortname' => 'ULAT',
+ 'hasdst' => FALSE ),
+ 'Asia/Ulan_Bator' => array(
+ 'offset' => 28800000,
+ 'longname' => "Ulaanbaatar Time",
+ 'shortname' => 'ULAT',
+ 'hasdst' => FALSE ),
+ 'Asia/Urumqi' => array(
+ 'offset' => 28800000,
+ 'longname' => "China Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'Australia/Perth' => array(
+ 'offset' => 28800000,
+ 'longname' => "Western Standard Time (Australia)",
+ 'shortname' => 'WST',
+ 'hasdst' => FALSE ),
+ 'Australia/West' => array(
+ 'offset' => 28800000,
+ 'longname' => "Western Standard Time (Australia)",
+ 'shortname' => 'WST',
+ 'hasdst' => FALSE ),
+ 'CTT' => array(
+ 'offset' => 28800000,
+ 'longname' => "China Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'Etc/GMT-8' => array(
+ 'offset' => 28800000,
+ 'longname' => "GMT+08:00",
+ 'shortname' => 'GMT+08:00',
+ 'hasdst' => FALSE ),
+ 'Hongkong' => array(
+ 'offset' => 28800000,
+ 'longname' => "Hong Kong Time",
+ 'shortname' => 'HKT',
+ 'hasdst' => FALSE ),
+ 'PRC' => array(
+ 'offset' => 28800000,
+ 'longname' => "China Standard Time",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'Singapore' => array(
+ 'offset' => 28800000,
+ 'longname' => "Singapore Time",
+ 'shortname' => 'SGT',
+ 'hasdst' => FALSE ),
+ 'Asia/Choibalsan' => array(
+ 'offset' => 32400000,
+ 'longname' => "Choibalsan Time",
+ 'shortname' => 'CHOT',
+ 'hasdst' => FALSE ),
+ 'Asia/Dili' => array(
+ 'offset' => 32400000,
+ 'longname' => "East Timor Time",
+ 'shortname' => 'TPT',
+ 'hasdst' => FALSE ),
+ 'Asia/Jayapura' => array(
+ 'offset' => 32400000,
+ 'longname' => "East Indonesia Time",
+ 'shortname' => 'EIT',
+ 'hasdst' => FALSE ),
+ 'Asia/Pyongyang' => array(
+ 'offset' => 32400000,
+ 'longname' => "Korea Standard Time",
+ 'shortname' => 'KST',
+ 'hasdst' => FALSE ),
+ 'Asia/Seoul' => array(
+ 'offset' => 32400000,
+ 'longname' => "Korea Standard Time",
+ 'shortname' => 'KST',
+ 'hasdst' => FALSE ),
+ 'Asia/Tokyo' => array(
+ 'offset' => 32400000,
+ 'longname' => "Japan Standard Time",
+ 'shortname' => 'JST',
+ 'hasdst' => FALSE ),
+ 'Asia/Yakutsk' => array(
+ 'offset' => 32400000,
+ 'longname' => "Yakutsk Time",
+ 'shortname' => 'YAKT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Yaktsk Summer Time",
+ 'dstshortname' => 'YAKST' ),
+ 'Etc/GMT-9' => array(
+ 'offset' => 32400000,
+ 'longname' => "GMT+09:00",
+ 'shortname' => 'GMT+09:00',
+ 'hasdst' => FALSE ),
+ 'JST' => array(
+ 'offset' => 32400000,
+ 'longname' => "Japan Standard Time",
+ 'shortname' => 'JST',
+ 'hasdst' => FALSE ),
+ 'Japan' => array(
+ 'offset' => 32400000,
+ 'longname' => "Japan Standard Time",
+ 'shortname' => 'JST',
+ 'hasdst' => FALSE ),
+ 'Pacific/Palau' => array(
+ 'offset' => 32400000,
+ 'longname' => "Palau Time",
+ 'shortname' => 'PWT',
+ 'hasdst' => FALSE ),
+ 'ROK' => array(
+ 'offset' => 32400000,
+ 'longname' => "Korea Standard Time",
+ 'shortname' => 'KST',
+ 'hasdst' => FALSE ),
+ 'ACT' => array(
+ 'offset' => 34200000,
+ 'longname' => "Central Standard Time (Northern Territory)",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'Australia/Adelaide' => array(
+ 'offset' => 34200000,
+ 'longname' => "Central Standard Time (South Australia)",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Summer Time (South Australia)",
+ 'dstshortname' => 'CST' ),
+ 'Australia/Broken_Hill' => array(
+ 'offset' => 34200000,
+ 'longname' => "Central Standard Time (South Australia/New South Wales)",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Summer Time (South Australia/New South Wales)",
+ 'dstshortname' => 'CST' ),
+ 'Australia/Darwin' => array(
+ 'offset' => 34200000,
+ 'longname' => "Central Standard Time (Northern Territory)",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'Australia/North' => array(
+ 'offset' => 34200000,
+ 'longname' => "Central Standard Time (Northern Territory)",
+ 'shortname' => 'CST',
+ 'hasdst' => FALSE ),
+ 'Australia/South' => array(
+ 'offset' => 34200000,
+ 'longname' => "Central Standard Time (South Australia)",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Summer Time (South Australia)",
+ 'dstshortname' => 'CST' ),
+ 'Australia/Yancowinna' => array(
+ 'offset' => 34200000,
+ 'longname' => "Central Standard Time (South Australia/New South Wales)",
+ 'shortname' => 'CST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Central Summer Time (South Australia/New South Wales)",
+ 'dstshortname' => 'CST' ),
+ 'AET' => array(
+ 'offset' => 36000000,
+ 'longname' => "Eastern Standard Time (New South Wales)",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Summer Time (New South Wales)",
+ 'dstshortname' => 'EST' ),
+ 'Antarctica/DumontDUrville' => array(
+ 'offset' => 36000000,
+ 'longname' => "Dumont-d'Urville Time",
+ 'shortname' => 'DDUT',
+ 'hasdst' => FALSE ),
+ 'Asia/Sakhalin' => array(
+ 'offset' => 36000000,
+ 'longname' => "Sakhalin Time",
+ 'shortname' => 'SAKT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Sakhalin Summer Time",
+ 'dstshortname' => 'SAKST' ),
+ 'Asia/Vladivostok' => array(
+ 'offset' => 36000000,
+ 'longname' => "Vladivostok Time",
+ 'shortname' => 'VLAT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Vladivostok Summer Time",
+ 'dstshortname' => 'VLAST' ),
+ 'Australia/ACT' => array(
+ 'offset' => 36000000,
+ 'longname' => "Eastern Standard Time (New South Wales)",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Summer Time (New South Wales)",
+ 'dstshortname' => 'EST' ),
+ 'Australia/Brisbane' => array(
+ 'offset' => 36000000,
+ 'longname' => "Eastern Standard Time (Queensland)",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'Australia/Canberra' => array(
+ 'offset' => 36000000,
+ 'longname' => "Eastern Standard Time (New South Wales)",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Summer Time (New South Wales)",
+ 'dstshortname' => 'EST' ),
+ 'Australia/Hobart' => array(
+ 'offset' => 36000000,
+ 'longname' => "Eastern Standard Time (Tasmania)",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Summer Time (Tasmania)",
+ 'dstshortname' => 'EST' ),
+ 'Australia/Lindeman' => array(
+ 'offset' => 36000000,
+ 'longname' => "Eastern Standard Time (Queensland)",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'Australia/Melbourne' => array(
+ 'offset' => 36000000,
+ 'longname' => "Eastern Standard Time (Victoria)",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Summer Time (Victoria)",
+ 'dstshortname' => 'EST' ),
+ 'Australia/NSW' => array(
+ 'offset' => 36000000,
+ 'longname' => "Eastern Standard Time (New South Wales)",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Summer Time (New South Wales)",
+ 'dstshortname' => 'EST' ),
+ 'Australia/Queensland' => array(
+ 'offset' => 36000000,
+ 'longname' => "Eastern Standard Time (Queensland)",
+ 'shortname' => 'EST',
+ 'hasdst' => FALSE ),
+ 'Australia/Sydney' => array(
+ 'offset' => 36000000,
+ 'longname' => "Eastern Standard Time (New South Wales)",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Summer Time (New South Wales)",
+ 'dstshortname' => 'EST' ),
+ 'Australia/Tasmania' => array(
+ 'offset' => 36000000,
+ 'longname' => "Eastern Standard Time (Tasmania)",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Summer Time (Tasmania)",
+ 'dstshortname' => 'EST' ),
+ 'Australia/Victoria' => array(
+ 'offset' => 36000000,
+ 'longname' => "Eastern Standard Time (Victoria)",
+ 'shortname' => 'EST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Eastern Summer Time (Victoria)",
+ 'dstshortname' => 'EST' ),
+ 'Etc/GMT-10' => array(
+ 'offset' => 36000000,
+ 'longname' => "GMT+10:00",
+ 'shortname' => 'GMT+10:00',
+ 'hasdst' => FALSE ),
+ 'Pacific/Guam' => array(
+ 'offset' => 36000000,
+ 'longname' => "Chamorro Standard Time",
+ 'shortname' => 'ChST',
+ 'hasdst' => FALSE ),
+ 'Pacific/Port_Moresby' => array(
+ 'offset' => 36000000,
+ 'longname' => "Papua New Guinea Time",
+ 'shortname' => 'PGT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Saipan' => array(
+ 'offset' => 36000000,
+ 'longname' => "Chamorro Standard Time",
+ 'shortname' => 'ChST',
+ 'hasdst' => FALSE ),
+ 'Pacific/Truk' => array(
+ 'offset' => 36000000,
+ 'longname' => "Truk Time",
+ 'shortname' => 'TRUT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Yap' => array(
+ 'offset' => 36000000,
+ 'longname' => "Yap Time",
+ 'shortname' => 'YAPT',
+ 'hasdst' => FALSE ),
+ 'Australia/LHI' => array(
+ 'offset' => 37800000,
+ 'longname' => "Load Howe Standard Time",
+ 'shortname' => 'LHST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Load Howe Summer Time",
+ 'dstshortname' => 'LHST' ),
+ 'Australia/Lord_Howe' => array(
+ 'offset' => 37800000,
+ 'longname' => "Load Howe Standard Time",
+ 'shortname' => 'LHST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Load Howe Summer Time",
+ 'dstshortname' => 'LHST' ),
+ 'Asia/Magadan' => array(
+ 'offset' => 39600000,
+ 'longname' => "Magadan Time",
+ 'shortname' => 'MAGT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Magadan Summer Time",
+ 'dstshortname' => 'MAGST' ),
+ 'Etc/GMT-11' => array(
+ 'offset' => 39600000,
+ 'longname' => "GMT+11:00",
+ 'shortname' => 'GMT+11:00',
+ 'hasdst' => FALSE ),
+ 'Pacific/Efate' => array(
+ 'offset' => 39600000,
+ 'longname' => "Vanuatu Time",
+ 'shortname' => 'VUT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Guadalcanal' => array(
+ 'offset' => 39600000,
+ 'longname' => "Solomon Is. Time",
+ 'shortname' => 'SBT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Kosrae' => array(
+ 'offset' => 39600000,
+ 'longname' => "Kosrae Time",
+ 'shortname' => 'KOST',
+ 'hasdst' => FALSE ),
+ 'Pacific/Noumea' => array(
+ 'offset' => 39600000,
+ 'longname' => "New Caledonia Time",
+ 'shortname' => 'NCT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Ponape' => array(
+ 'offset' => 39600000,
+ 'longname' => "Ponape Time",
+ 'shortname' => 'PONT',
+ 'hasdst' => FALSE ),
+ 'SST' => array(
+ 'offset' => 39600000,
+ 'longname' => "Solomon Is. Time",
+ 'shortname' => 'SBT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Norfolk' => array(
+ 'offset' => 41400000,
+ 'longname' => "Norfolk Time",
+ 'shortname' => 'NFT',
+ 'hasdst' => FALSE ),
+ 'Antarctica/McMurdo' => array(
+ 'offset' => 43200000,
+ 'longname' => "New Zealand Standard Time",
+ 'shortname' => 'NZST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "New Zealand Daylight Time",
+ 'dstshortname' => 'NZDT' ),
+ 'Antarctica/South_Pole' => array(
+ 'offset' => 43200000,
+ 'longname' => "New Zealand Standard Time",
+ 'shortname' => 'NZST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "New Zealand Daylight Time",
+ 'dstshortname' => 'NZDT' ),
+ 'Asia/Anadyr' => array(
+ 'offset' => 43200000,
+ 'longname' => "Anadyr Time",
+ 'shortname' => 'ANAT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Anadyr Summer Time",
+ 'dstshortname' => 'ANAST' ),
+ 'Asia/Kamchatka' => array(
+ 'offset' => 43200000,
+ 'longname' => "Petropavlovsk-Kamchatski Time",
+ 'shortname' => 'PETT',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Petropavlovsk-Kamchatski Summer Time",
+ 'dstshortname' => 'PETST' ),
+ 'Etc/GMT-12' => array(
+ 'offset' => 43200000,
+ 'longname' => "GMT+12:00",
+ 'shortname' => 'GMT+12:00',
+ 'hasdst' => FALSE ),
+ 'Kwajalein' => array(
+ 'offset' => 43200000,
+ 'longname' => "Marshall Islands Time",
+ 'shortname' => 'MHT',
+ 'hasdst' => FALSE ),
+ 'NST' => array(
+ 'offset' => 43200000,
+ 'longname' => "New Zealand Standard Time",
+ 'shortname' => 'NZST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "New Zealand Daylight Time",
+ 'dstshortname' => 'NZDT' ),
+ 'NZ' => array(
+ 'offset' => 43200000,
+ 'longname' => "New Zealand Standard Time",
+ 'shortname' => 'NZST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "New Zealand Daylight Time",
+ 'dstshortname' => 'NZDT' ),
+ 'Pacific/Auckland' => array(
+ 'offset' => 43200000,
+ 'longname' => "New Zealand Standard Time",
+ 'shortname' => 'NZST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "New Zealand Daylight Time",
+ 'dstshortname' => 'NZDT' ),
+ 'Pacific/Fiji' => array(
+ 'offset' => 43200000,
+ 'longname' => "Fiji Time",
+ 'shortname' => 'FJT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Funafuti' => array(
+ 'offset' => 43200000,
+ 'longname' => "Tuvalu Time",
+ 'shortname' => 'TVT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Kwajalein' => array(
+ 'offset' => 43200000,
+ 'longname' => "Marshall Islands Time",
+ 'shortname' => 'MHT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Majuro' => array(
+ 'offset' => 43200000,
+ 'longname' => "Marshall Islands Time",
+ 'shortname' => 'MHT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Nauru' => array(
+ 'offset' => 43200000,
+ 'longname' => "Nauru Time",
+ 'shortname' => 'NRT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Tarawa' => array(
+ 'offset' => 43200000,
+ 'longname' => "Gilbert Is. Time",
+ 'shortname' => 'GILT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Wake' => array(
+ 'offset' => 43200000,
+ 'longname' => "Wake Time",
+ 'shortname' => 'WAKT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Wallis' => array(
+ 'offset' => 43200000,
+ 'longname' => "Wallis & Futuna Time",
+ 'shortname' => 'WFT',
+ 'hasdst' => FALSE ),
+ 'NZ-CHAT' => array(
+ 'offset' => 45900000,
+ 'longname' => "Chatham Standard Time",
+ 'shortname' => 'CHAST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Chatham Daylight Time",
+ 'dstshortname' => 'CHADT' ),
+ 'Pacific/Chatham' => array(
+ 'offset' => 45900000,
+ 'longname' => "Chatham Standard Time",
+ 'shortname' => 'CHAST',
+ 'hasdst' => TRUE,
+ 'dstlongname' => "Chatham Daylight Time",
+ 'dstshortname' => 'CHADT' ),
+ 'Etc/GMT-13' => array(
+ 'offset' => 46800000,
+ 'longname' => "GMT+13:00",
+ 'shortname' => 'GMT+13:00',
+ 'hasdst' => FALSE ),
+ 'Pacific/Enderbury' => array(
+ 'offset' => 46800000,
+ 'longname' => "Phoenix Is. Time",
+ 'shortname' => 'PHOT',
+ 'hasdst' => FALSE ),
+ 'Pacific/Tongatapu' => array(
+ 'offset' => 46800000,
+ 'longname' => "Tonga Time",
+ 'shortname' => 'TOT',
+ 'hasdst' => FALSE ),
+ 'Etc/GMT-14' => array(
+ 'offset' => 50400000,
+ 'longname' => "GMT+14:00",
+ 'shortname' => 'GMT+14:00',
+ 'hasdst' => FALSE ),
+ 'Pacific/Kiritimati' => array(
+ 'offset' => 50400000,
+ 'longname' => "Line Is. Time",
+ 'shortname' => 'LINT',
+ 'hasdst' => FALSE )
+);
+
+$names = timezone_identifiers_list();
+$offsets = timezone_abbreviations_list();
+$abbrs = array_keys($offsets);
+$timezones = array();
+foreach ($data as $name => $value) {
+ if (in_array($name, $names)) {
+ if (!empty($value['dstshortname'])) {
+ $abbr = strtolower($value['dstshortname']);
+ foreach ((array) $offsets[$abbr] as $offset) {
+ if ($offset['timezone_id'] == $name && $offset['dst'] == 1) {
+ $timezones[$abbr][] = $offset;
+ }
+ }
+ }
+ $abbr = strtolower($value['shortname']);
+ foreach ((array) $offsets[$abbr] as $offset) {
+ if ($offset['timezone_id'] == $name && empty($offset['dst'])) {
+ $timezones[$abbr][] = $offset;
+ }
+ }
+ }
+}
+ksort($timezones);
+print_r($timezones);
+//print var_export(serialize($timezones));
\ No newline at end of file
diff --git a/sites/all/modules/date/date_php4/date_php4_tz_identifiers.inc b/sites/all/modules/date/date_php4/date_php4_tz_identifiers.inc
new file mode 100644
index 0000000..c8ef6b8
--- /dev/null
+++ b/sites/all/modules/date/date_php4/date_php4_tz_identifiers.inc
@@ -0,0 +1,11 @@
+ $t('Date Popup requirements'),
+ 'value' => $t('The Date Popup module needs code added by the jQuery UI module. Install that module as soon as possible.'),
+ 'severity' => REQUIREMENT_WARNING,
+ );
+ }
+ break;
+ }
+ return $requirements;
+}
+
+/**
+ * Implementation of hook_install().
+ */
+function date_popup_install() {
+ if (module_exists('content')) {
+ drupal_load('module', 'content');
+ if (!db_table_exists(content_instance_tablename())) {
+ return;
+ }
+ if (module_exists('date_repeat')) {
+ db_query("UPDATE {". content_instance_tablename() ."} SET widget_active=1 WHERE widget_type='%s' OR widget_type='%s'", 'date_popup', 'date_popup_repeat');
+ }
+ else {
+ db_query("UPDATE {". content_instance_tablename() ."} SET widget_active=1 WHERE widget_type='%s'", 'date_popup');
+ }
+ content_clear_type_cache(TRUE);
+ }
+}
+
+/**
+ * Implementation of hook_uninstall().
+ */
+function date_popup_uninstall() {
+ if (module_exists('content')) {
+ drupal_load('module', 'content');
+ if (!db_table_exists(content_instance_tablename())) {
+ return;
+ }
+ if (module_exists('date_repeat')) {
+ db_query("UPDATE {". content_instance_tablename() ."} SET widget_active=0 WHERE widget_type='%s' OR widget_type='%s'", 'date_popup', 'date_popup_repeat');
+ }
+ else {
+ db_query("UPDATE {". content_instance_tablename() ."} SET widget_active=0 WHERE widget_type='%s'", 'date_popup');
+ }
+ content_clear_type_cache(TRUE);
+ }
+}
+
+/**
+ * Implementation of hook_enable().
+ */
+function date_popup_enable() {
+ if (module_exists('content')) {
+ drupal_load('module', 'content');
+ if (!db_table_exists(content_instance_tablename())) {
+ return;
+ }
+ if (module_exists('date_repeat')) {
+ db_query("UPDATE {". content_instance_tablename() ."} SET widget_active=1 WHERE widget_type='%s' OR widget_type='%s'", 'date_popup', 'date_popup_repeat');
+ }
+ else {
+ db_query("UPDATE {". content_instance_tablename() ."} SET widget_active=1 WHERE widget_type='%s'", 'date_popup');
+ }
+ content_clear_type_cache(TRUE);
+ }
+}
+
+/**
+ * Implementation of hook_disable().
+ */
+function date_popup_disable() {
+ if (module_exists('content')) {
+ drupal_load('module', 'content');
+ if (!db_table_exists(content_instance_tablename())) {
+ return;
+ }
+ if (module_exists('date_repeat')) {
+ db_query("UPDATE {". content_instance_tablename() ."} SET widget_active=0 WHERE widget_type='%s' OR widget_type='%s'", 'date_popup', 'date_popup_repeat');
+ }
+ else {
+ db_query("UPDATE {". content_instance_tablename() ."} SET widget_active=0 WHERE widget_type='%s'", 'date_popup');
+ }
+ content_clear_type_cache(TRUE);
+ }
+}
+
+/**
+ * Update default path for date popup css
+ */
+function date_popup_update_6001() {
+ $ret = array();
+ $version = function_exists('jquery_ui_get_version') ? jquery_ui_get_version() : '1.6';
+ switch ($version) {
+ case '1.6':
+ $path = drupal_get_path('module', 'date_popup') . '/themes/datepicker.css';
+ break;
+ default:
+ $path = drupal_get_path('module', 'date_popup') . '/themes/datepicker.1.7.css';
+ break;
+ }
+ variable_set('date_popup_css_file', $path);
+ if (!module_exists('jquery_ui')) {
+ drupal_set_message('The jQuery UI module is now required when using Date Popup. See the jQuery UI page for installation instructions.', 'error');
+ }
+ return $ret;
+}
diff --git a/sites/all/modules/date/date_popup/date_popup.js b/sites/all/modules/date/date_popup/date_popup.js
new file mode 100644
index 0000000..f3c808e
--- /dev/null
+++ b/sites/all/modules/date/date_popup/date_popup.js
@@ -0,0 +1,33 @@
+
+/**
+ * Attaches the calendar behavior to all required fields
+ */
+Drupal.behaviors.date_popup = function (context) {
+ for (var id in Drupal.settings.datePopup) {
+ $('#'+ id).bind('focus', Drupal.settings.datePopup[id], function(e) {
+ if (!$(this).hasClass('date-popup-init')) {
+ var datePopup = e.data;
+ // Explicitely filter the methods we accept.
+ switch (datePopup.func) {
+ case 'datepicker':
+ $(this)
+ .datepicker(datePopup.settings)
+ .addClass('date-popup-init')
+ $(this).click(function() {
+ $(this).focus();
+ });
+ break;
+
+ case 'timeEntry':
+ $(this)
+ .timeEntry(datePopup.settings)
+ .addClass('date-popup-init')
+ $(this).click(function() {
+ $(this).focus();
+ });
+ break;
+ }
+ }
+ });
+ }
+};
diff --git a/sites/all/modules/date/date_popup/date_popup.module b/sites/all/modules/date/date_popup/date_popup.module
new file mode 100644
index 0000000..bd1191a
--- /dev/null
+++ b/sites/all/modules/date/date_popup/date_popup.module
@@ -0,0 +1,685 @@
+language != 'en') {
+ jquery_ui_add("i18n/ui.datepicker-{$language->language}");
+ }
+ }
+ if (variable_get('date_popup_timepicker', 'default') == 'default') {
+ drupal_add_js($path .'/lib/jquery.timeentry.pack.js');
+ }
+ $loaded = TRUE;
+}
+
+function date_popup_css_default() {
+ if (!module_exists('jquery_ui')) {
+ return '';
+ }
+ $version = jquery_ui_get_version();
+ $jquery_ui_path = drupal_get_path('module', 'jquery_ui');
+ switch ($version) {
+ case '1.6':
+ return drupal_get_path('module', 'date_popup') .'/themes/datepicker.css';
+ default:
+ return drupal_get_path('module', 'date_popup') .'/themes/datepicker.1.7.css';
+ }
+}
+
+function date_popup_css_options() {
+ $paths = array();
+ if (!module_exists('jquery_ui')) {
+ return $paths;
+ }
+ $version = jquery_ui_get_version();
+ $jquery_ui_path = jquery_ui_get_path();
+ switch ($version) {
+ case '1.6':
+ $paths[drupal_get_path('module', 'date_popup') .'/themes/datepicker.css'] = t('Date Popup default');
+ $paths[$jquery_ui_path .'/themes/default/ui.datepicker.css'] = t('jQuery UI default');
+ break;
+ default:
+ $paths[drupal_get_path('module', 'date_popup') .'/themes/datepicker.1.7.css'] = t('Date Popup default');
+ $paths[$jquery_ui_path .'/themes/base/ui.datepicker.css'] = t('jQuery UI default');
+ break;
+ }
+ // Populate options array with available themes from jQuery UI.
+ // Each theme must be placed in its own subdirectory of jquery.ui/themes/,
+ // e.g., jquery.ui/themes/cupertino, jquery.ui/themes/ui-lightness, etc.
+ // All themes can be downloaded from
+ // http://jquery-ui.googlecode.com/files/jquery-ui-themes-1.7.zip
+ foreach (scandir($jquery_ui_path .'/themes/') as $dir) {
+ $full_dir_path = $jquery_ui_path .'/themes/'. $dir;
+ if (is_dir($full_dir_path) && $dir != '.' && $dir != '..' && $dir != 'base') {
+ $paths[$full_dir_path .'/ui.datepicker.css'] = t('jQuery UI @theme', array('@theme' => $dir));
+ }
+ }
+ return $paths;
+}
+
+/**
+ * Implementation of hook_init().
+ */
+function date_popup_init() {
+ global $user;
+ if (!module_exists('jquery_ui') || !function_exists('jquery_ui_get_path')) {
+ if ($user->uid == 1) {
+ drupal_set_message(t('The Date Popup module now requires the jQuery UI module version 6.x-1.5 or higher as a source for the datepicker. Please install it immediately.', array('@link' => 'http://drupal.org/project/jquery_ui')), 'error');
+ }
+ return;
+ }
+
+ $date_popup_css_file = variable_get('date_popup_css_file', date_popup_css_default());
+
+ // Force loading base jquery-ui.css when using date_popup default theme,
+ // otherwise the popup calendar will be displayed with no theme at all.
+ if ($date_popup_css_file == date_popup_css_default()) {
+ drupal_add_css(jquery_ui_get_path() .'/themes/base/jquery-ui.css');
+ }
+ // Otherwise, load the CSS file in the corresponding theme directory.
+ else {
+ drupal_add_css(dirname($date_popup_css_file) .'/jquery-ui.css');
+ }
+ drupal_add_css($date_popup_css_file);
+
+ if (variable_get('date_popup_timepicker', 'default') == 'default') {
+ drupal_add_css(drupal_get_path('module', 'date_popup') .'/themes/jquery.timeentry.css');
+ }
+}
+
+ /**
+ * Create a unique CSS id name and output a single inline JS block for
+ * each startup function to call and settings array to pass it. This
+ * used to create a unique CSS class for each unique combination of
+ * function and settings, but using classes requires a DOM traversal
+ * and is much slower than an id lookup. The new approach returns to
+ * requiring a duplicate copy of the settings/code for every element
+ * that uses them, but is much faster. We could combine the logic by
+ * putting the ids for each unique function/settings combo into
+ * Drupal.settings and searching for each listed id.
+ *
+ * @param $pfx
+ * The CSS class prefix to search the DOM for.
+ * TODO : unused ?
+ * @param $func
+ * The jQuery function to invoke on each DOM element containing the
+ * returned CSS class.
+ * @param $settings
+ * The settings array to pass to the jQuery function.
+ * @returns
+ * The CSS id to assign to the element that should have
+ * $func($settings) invoked on it.
+ */
+function date_popup_js_settings_id($id, $func, $settings) {
+ static $js_added = FALSE;
+ static $id_count = array();
+
+ // Make sure popup date selector grid is in correct year.
+ if (!empty($settings['yearRange'])) {
+ $parts = explode(':', $settings['yearRange']);
+ // Set the default date to 0 or the lowest bound if the date ranges do not include the current year
+ // Necessary for the datepicker to render and select dates correctly
+ $defaultDate = ($parts[0] > 0 || 0 > $parts[1]) ? $parts[0] : 0;
+
+ // The 1.7 version of datepicker renders the range of year options
+ // relative to the drawn year in the popup, and will re-render the options
+ // whenever the year changes.
+ if (strpos(jquery_ui_get_version(), '1.7') === 0 && ($parts[0] >= 0 || 0 >= $parts[1])) {
+ $range = max($parts) - min($parts);
+ $defaultDate = $parts[0];
+ $settings['yearRange'] = '-' . $range . ':' . '+' . $range;
+ }
+ $settings += array('defaultDate' => (string) $defaultDate . 'y');
+ }
+
+ if (!$js_added) {
+ drupal_add_js(drupal_get_path('module', 'date_popup') .'/date_popup.js');
+ $js_added = TRUE;
+ }
+
+ // We use a static array to account for possible multiple form_builder()
+ // calls in the same request (form instance on 'Preview').
+ if (!isset($id_count[$id])) {
+ $id_count[$id] = 0;
+ }
+
+// It looks like we need the additional id_count for this to
+// work correctly when there are multiple values.
+// $return_id = "$id-$func-popup";
+ $return_id = "$id-$func-popup-". $id_count[$id]++;
+ $js_settings['datePopup'][$return_id] = array(
+ 'func' => $func,
+ 'settings' => $settings
+ );
+ drupal_add_js($js_settings, 'setting');
+ return $return_id;
+}
+
+function date_popup_theme() {
+ return array(
+ 'date_popup' => array('arguments' => array('element' => NULL)),
+ );
+}
+
+/**
+ * Implementation of hook_elements().
+ *
+ * Set the #type to date_popup and fill the element #default_value with
+ * a date adjusted to the proper local timezone in datetime format (YYYY-MM-DD HH:MM:SS).
+ *
+ * The element will create two textfields, one for the date and one for the
+ * time. The date textfield will include a jQuery popup calendar date picker,
+ * and the time textfield uses a jQuery timepicker.
+ *
+ * NOTE - Converting a date stored in the database from UTC to the local zone
+ * and converting it back to UTC before storing it is not handled by this
+ * element and must be done in pre-form and post-form processing!!
+ *
+ * #date_timezone
+ * The local timezone to be used to create this date.
+ *
+ * #date_format
+ * Unlike earlier versions of this popup, most formats will work.
+ *
+ * #date_increment
+ * Increment minutes and seconds by this amount, default is 1.
+ *
+ * #date_year_range
+ * The number of years to go back and forward in a year selector,
+ * default is -3:+3 (3 back and 3 forward).
+ *
+ */
+function date_popup_elements() {
+ return array(
+ 'date_popup' => array(
+ '#input' => TRUE,
+ '#tree' => TRUE,
+ '#date_timezone' => date_default_timezone_name(),
+ '#date_format' => variable_get('date_format_short', 'm/d/Y - H:i'),
+ '#date_increment' => 1,
+ '#date_year_range' => '-3:+3',
+ '#process' => array('date_popup_process'),
+ ),
+ );
+}
+
+/**
+ * Javascript popup element processing.
+ * Add popup attributes to $element.
+ *
+ * In regular FAPI processing $element['#value'] will contain a string
+ * value before the form is submitted, and an array during submission.
+ *
+ * In regular FAPI processing $edit is empty until the form is submitted
+ * when it will contain an array.
+ *
+ * Views widget processing now receives the same values as normal FAPI
+ * processing (that was not true in Views 1).
+ *
+ */
+function date_popup_process($element, $edit, $form_state, $form) {
+ date_popup_load();
+ require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_elements.inc');
+
+ $date = NULL;
+ $granularity = date_format_order($element['#date_format']);
+
+ if (!empty($edit) && is_array($edit) && !empty($edit['date'])) {
+ $datetime = date_popup_input_value($element);
+ $date = date_make_date($datetime, $element['#date_timezone'], DATE_DATETIME, $granularity);
+ }
+ elseif (!empty($element['#value'])) {
+ $date = date_make_date($element['#value'], $element['#date_timezone'], DATE_DATETIME, $granularity);
+ }
+
+ date_increment_round($date, $element['#date_increment']);
+ $granularity = date_format_order($element['#date_format']);
+ $element['#tree'] = TRUE;
+ $element['#granularity'] = $granularity;
+ $element['date'] = date_popup_process_date($element, $edit, $date);
+ $element['time'] = date_popup_process_time($element, $edit, $date);
+
+ if (isset($element['#element_validate'])) {
+ array_push($element['#element_validate'], 'date_popup_validate');
+ }
+ else {
+ $element['#element_validate'] = array('date_popup_validate');
+ }
+ return $element;
+}
+
+/**
+ * Process the date portion of the element.
+ */
+function date_popup_process_date(&$element, $edit = NULL, $date = NULL) {
+ $granularity = $element['#granularity'];
+ $date_granularity = array_intersect($granularity, array('month', 'day', 'year'));
+ $time_granularity = array_intersect($granularity, array('hour', 'minute', 'second'));
+ $date_format = (date_limit_format($element['#date_format'], $date_granularity));
+ if (empty($date_granularity)) return array();
+
+ // The datepicker can't handle zero or negative values like 0:+1
+ // even though the Date API can handle them, so rework the value
+ // we pass to the datepicker to use defaults it can accept (such as +0:+1)
+ // date_range_string() adds the necessary +/- signs to the range string.
+ $range = date_range_years($element['#date_year_range'], $date);
+ $year_range = date_range_string($range);
+
+ $settings = array(
+ 'prevText' => '«',
+ 'nextText' => '»',
+ 'currentText' => date_t('Today', 'date_nav'),
+ 'changeMonth' => TRUE,
+ 'changeYear' => TRUE,
+ 'clearText' => t('Clear'),
+ 'closeText' => t('Close'),
+ 'firstDay' => intval(variable_get('date_first_day', 1)),
+ 'dayNames' => date_week_days(TRUE),
+ 'dayNamesShort' => date_week_days_abbr(TRUE, TRUE, 3),
+ 'dayNamesMin' => date_week_days_abbr(TRUE, TRUE, 2),
+ 'monthNames' => array_values(date_month_names(TRUE)),
+ 'monthNamesShort' => array_values(date_month_names_abbr(TRUE)),
+ //'buttonImage' => base_path() . drupal_get_path('module', 'date_api') ."/images/calendar.png",
+ //'buttonImageOnly' => TRUE,
+ 'autoPopUp' => 'focus',
+ 'closeAtTop' => FALSE,
+ 'speed' => 'immediate',
+ 'dateFormat' => date_popup_format_to_popup($date_format, 'datepicker'),
+ 'yearRange' => $year_range,
+ // Custom setting, will be expanded in Drupal.behaviors.date_popup()
+ 'fromTo' => isset($fromto),
+ );
+
+ // Create a unique id for each set of custom settings.
+ $id = date_popup_js_settings_id($element['#id'], 'datepicker', $settings);
+
+ // Manually build this element and set the value - this will prevent corrupting
+ // the parent value
+ $parents = array_merge($element['#parents'], array('date'));
+ $sub_element = array(
+ '#type' => 'textfield',
+ '#default_value' => (!empty($element['#value']) || !empty($edit['date'])) && is_object($date) ? date_format_date($date, 'custom', $date_format) : '',
+ '#id' => $id,
+ '#input' => FALSE,
+ '#size' => !empty($element['#size']) ? $element['#size'] : 20,
+ '#maxlength' => !empty($element['#maxlength']) ? $element['#maxlength'] : 30,
+ '#attributes' => $element['#attributes'],
+ '#parents' => $parents,
+ '#name' => array_shift($parents) . '['. implode('][', $parents) .']'
+ );
+ $sub_element['#value'] = $sub_element['#default_value'];
+
+ // TODO, figure out exactly when we want this description. In many places it is not desired.
+ $sub_element['#description'] = ' '. t('Format: @date', array('@date' => date_format_date(date_now(), 'custom', $date_format)));
+ return $sub_element;
+}
+
+/**
+ * Process the time portion of the element.
+ */
+function date_popup_process_time(&$element, $edit = NULL, $date = NULL) {
+ $granularity = $element['#granularity'];
+ $time_granularity = array_intersect($granularity, array('hour', 'minute', 'second'));
+ $time_format = date_popup_format_to_popup_time(date_limit_format($element['#date_format'], $time_granularity));
+ if (empty($time_granularity)) return array();
+
+ $spinner_text = array(t('Now'), t('Previous field'), t('Next field'), t('Increment'), t('Decrement'));
+ $settings = array(
+ 'show24Hours' => strpos($element['#date_format'], 'H') !== FALSE ? TRUE : FALSE,
+ 'showSeconds' => (in_array('second', $granularity) ? TRUE : FALSE),
+ 'timeSteps' => array(1, intval($element['#date_increment']), (in_array('second', $granularity) ? $element['#date_increment'] : 0)),
+ 'spinnerImage' => '',
+ 'fromTo' => isset($fromto),
+ );
+
+ // Create a unique id for each set of custom settings.
+ $id = date_popup_js_settings_id($element['#id'], 'timeEntry', $settings);
+
+ // Manually build this element and set the value - this will prevent corrupting
+ // the parent value
+ $parents = array_merge($element['#parents'], array('time'));
+ $sub_element = array(
+ '#type' => 'textfield',
+ '#default_value' => (!empty($element['#value']) || !empty($edit['time'])) && is_object($date) ? date_format_date($date, 'custom', $time_format) : '',
+ '#id' => $id,
+ '#input' => FALSE,
+ '#size' => 10,
+ '#maxlength' => 10,
+ '#parents' => $parents,
+ '#name' => array_shift($parents) . '['. implode('][', $parents) .']'
+ );
+ $sub_element['#value'] = $sub_element['#default_value'];
+
+ // TODO, figure out exactly when we want this description. In many places it is not desired.
+ $sub_element['#description'] = t('Format: @date', array('@date' => date_format_date(date_now(), 'custom', $time_format)));
+ return ($sub_element);
+}
+
+/**
+ * Massage the input values back into a single date.
+ *
+ * When used as a Views widget, the validation step always gets triggered,
+ * even with no form submission. Before form submission $element['#value']
+ * contains a string, after submission it contains an array.
+ *
+ */
+function date_popup_validate($element, &$form_state) {
+ if (is_string($element['#value'])) {
+ return;
+ }
+ $granularity = $element['#granularity'];
+ $date_granularity = array_intersect($granularity, array('month', 'day', 'year'));
+ $time_granularity = array_intersect($granularity, array('hour', 'minute', 'second'));
+ $label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
+ $label = t($label);
+
+ // If the field is empty and not required, set it to empty and return.
+ // If the field is empty and required, set error message and return.
+ $error_field = implode('][', $element['#parents']);
+ if (empty($element['#value']['date'])) {
+ if ($element['#required']) {
+ // Set message on both date and time to get them highlighted properly.
+ $message = t('Field %field is required.', array('%field' => $label));
+ if (!empty($date_granularity)) {
+ form_set_error($error_field .'][date', $message);
+ $message = ' ';
+ }
+ if (!empty($time_granularity)) {
+ form_set_error($error_field .'][time', $message);
+ }
+ }
+ form_set_value($element, NULL, $form_state);
+ return;
+ }
+
+ require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_elements.inc');
+ date_popup_load();
+ $value = date_popup_input_value($element);
+
+ // If the created date is valid, set it.
+ if (!empty($value)) {
+ form_set_value($element, $value, $form_state);
+ return;
+ }
+ else {
+ // Set message on both date and time to get them highlighted properly.
+ $message = t('Field %field is invalid.', array('%field' => $label));
+ if (!empty($date_granularity)) {
+ form_set_error($error_field .'][date', $message);
+ $message = ' ';
+ }
+ if (!empty($time_granularity)) {
+ form_set_error($error_field .'][time', $message);
+ }
+ }
+ form_set_value($element, NULL, $form_state);
+}
+
+/**
+ * Helper function for extracting a date value out of user input.
+ *
+ * @param autocomplete
+ * Should we add a time value to complete the date if there is no time?
+ * Useful anytime the time value is optional.
+ */
+function date_popup_input_value($element, $auto_complete = FALSE) {
+ date_popup_load();
+ $granularity = date_format_order($element['#date_format']);
+ $format = $element['#date_format'];
+ $format = strtr($format, timepicker_format_replacements());
+ $format = date_limit_format($format, $granularity);
+ // Evaluate date and time parts separately since we can't know or care
+ // how they're combined in the complete date format.
+ $time_format = date_limit_format($format, array('hour', 'minute', 'second'));
+ $date_format = date_limit_format($format, array('year', 'month', 'day'));
+ $value = '';
+ if (is_array($element['#value']) && !empty($element['#value']['date'])) {
+ $date = date_convert_from_custom(trim(!empty($element['#value']['date']) ? $element['#value']['date'] : ''), $date_format);
+ $time = date_convert_from_custom(trim(!empty($element['#value']['time']) ? $element['#value']['time'] : ''), $time_format);
+ $value = trim(drupal_substr($date, 0, 10) .' '. drupal_substr($time, 11, 8));
+ }
+
+ if (date_is_valid($value, DATE_DATETIME, $granularity)) {
+ $date = date_make_date($value, $element['#date_timezone'], DATE_DATETIME, $granularity);
+ $value = date_convert($date, DATE_OBJECT, DATE_DATETIME);
+ return $value;
+ }
+ return NULL;
+}
+
+/**
+ * Allowable time formats.
+ */
+function date_popup_time_formats($with_seconds = FALSE) {
+ return array(
+ 'H:i:s',
+ 'h:i:sA',
+ );
+}
+
+/**
+ * Format options array.
+ *
+ * There are just a few options available for the earlier 'calendar'
+ * version.
+ */
+function date_popup_formats() {
+ return array_keys(date_format_options());
+}
+
+/**
+ * Store personalized format options for each user.
+ *
+ * TODO see what is needed to remove this completely.
+ * It is now only used by Date Popup and not really needed there.
+ *
+ * @return array
+ */
+function date_format_options() {
+ global $user;
+ $options = array();
+ $formats = date_get_formats();
+ $options = array();
+ module_load_include('inc', 'date', 'date_admin');
+ $now = date_example_date();
+ if (!empty($now)) {
+ foreach ($formats as $type => $format_types) {
+ foreach ($format_types as $format => $format_attributes) {
+ // Create an option that shows date only without time, along with the
+ // default string which has both date and time.
+ $no_time = date_limit_format($format, array('month', 'day', 'year'));
+ $zones = array('', 'O', 'P', 'e');
+ foreach ($zones as $zone) {
+ $time_format = !empty($zone) ? $format .' '. $zone : $format;
+ $options[$no_time] = date_format_date($now, 'custom', $no_time);
+ $options[$time_format] = date_format_date($now, 'custom', $time_format);
+ }
+ }
+ }
+ asort($options);
+ }
+ return $options;
+}
+
+/**
+ * Recreate a date format string so it has the values popup expects.
+ *
+ * @param string $format
+ * a normal date format string, like Y-m-d
+ * @return string
+ * A format string in popup format, like YMD-, for the
+ * earlier 'calendar' version, or m/d/Y for the later 'datepicker'
+ * version.
+ */
+function date_popup_format_to_popup($format) {
+ if (empty($format)) {
+ $format = 'Y-m-d';
+ }
+ $replace = datepicker_format_replacements();
+ return strtr($format, $replace);
+}
+
+/**
+ * Recreate a date format string so it has the values popup expects.
+ *
+ * @param string $format
+ * a normal date format string, like Y-m-d
+ * @return string
+ * a format string in popup format, like YMD-
+ */
+function date_popup_format_to_popup_time($format) {
+ if (empty($format)) {
+ $format = 'H:i';
+ }
+ $format = strtr($format, timepicker_format_replacements());
+ $format = str_replace(array(' ', '/', '-', '.', ',', 'F', 'M', 'l', 'z', 'w', 'W', 'd', 'j', 'm', 'n', 'y', 'Y'), '', $format);
+ return $format;
+}
+
+/**
+ * Reconstruct popup format string into normal format string.
+ *
+ * @param string $format
+ * a string in popup format, like YMD-
+ * @return string
+ * a normal date format string, like Y-m-d
+ */
+function date_popup_popup_to_format($format) {
+ $replace = array_flip(datepicker_format_replacements());
+ return strtr($format, $replace);
+}
+
+function timepicker_format_replacements() {
+ return array(
+ 'G' => 'H',
+ 'g' => 'h',
+ 'a' => 'A',
+ ' a' => 'A',
+ ' A' => 'A',
+ );
+}
+
+/**
+ * The format replacement patterns for the new datepicker.
+ */
+function datepicker_format_replacements() {
+ return array(
+ 'd' => 'dd',
+ 'j' => 'd',
+ 'l' => 'DD',
+ 'D' => 'D',
+ 'm' => 'mm',
+ 'n' => 'm',
+ 'F' => 'MM',
+ 'M' => 'M',
+ 'Y' => 'yy',
+ 'y' => 'y',
+ );
+}
+
+/**
+ * Format a date popup element.
+ *
+ * Use a class that will float date and time next to each other.
+ */
+function theme_date_popup($element) {
+ $output = '';
+ $class = 'container-inline-date form-item';
+ // Add #date_float to allow date parts to float together on the same line.
+ if (empty($element['#date_float'])) {
+ $class .= ' date-clear-block';
+ }
+ if (isset($element['#children'])) {
+ $output = $element['#children'];
+ }
+ return '
'. theme('form_element', $element, $output) .'
';
+}
+
+/**
+ * Implementation of hook_menu().
+ */
+function date_popup_menu() {
+ $items = array();
+
+ $items['admin/settings/date_popup'] = array(
+ 'title' => 'Date Popup Configuration',
+ 'description' => 'Allows the user to configure the Date Popup settings.',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('date_popup_settings'),
+ 'access callback' => 'user_access',
+ 'access arguments' => array('administer site configuration'),
+ 'type' => MENU_NORMAL_ITEM,
+ );
+ return $items;
+}
+/**
+ * General configuration form for controlling the Date Popup behaviour.
+ */
+function date_popup_settings() {
+ $form['date_popup_css_file'] = array(
+ '#type' => 'select',
+ '#title' => t('Datepicker css'),
+ '#description' => t('Choose the css to use for the jQuery UI datepicker.'),
+ '#options' => date_popup_css_options(),
+ '#default_value' => variable_get('date_popup_css_file', date_popup_css_default()),
+ );
+ $form['date_popup_css_file']['#prefix'] = t('
The Date Popup calendar datepicker uses the jQuery UI datepicker. You must install the jQuery UI module for this to work. It has its own css file, or there is a Drupal adaptation included in Date Popup that you can use.
The Date Popup module uses a jQuery timepicker module. There is no "official" jQuery UI timepicker, and not everyone likes the one that is included here. If you do not want to use the timepicker, you can turn it off below and users will get a regular textfield instead.
');
+
+ $css = <<The Date Popup calendar includes some css for IE6 that breaks css validation. Since IE 6 is now superceded by IE 7 and IE 8, the special css for IE 6 has been removed from the regular css used by the Date Popup. If you find you need that css after all, you can add it back in your theme. Look at the way the Garland theme adds special IE-only css in in its page.tpl.php file. The css you need is:
\ No newline at end of file
diff --git a/sites/all/modules/date/help/date-copy.html b/sites/all/modules/date/help/date-copy.html
new file mode 100644
index 0000000..fd0ff08
--- /dev/null
+++ b/sites/all/modules/date/help/date-copy.html
@@ -0,0 +1,13 @@
+The Date Copy module allows you to import date data into CCK nodes. Currently you can convert Event nodes to CCK nodes or import date data from an iCal feed.
+
+
Importing from Event Nodes
+If you currently have date information in Event nodes and want to get the event dates into CCK Date fields instead, you can do this using the Date Copy module included with the Date module.
+
+
+
First, create the content type you want to import your events into and make sure the content type has a CCK date field and a field to hold the event description (either a body or a text field). You can create a new content type for this purpose or add a CCK date field to the current event type, depending on whether you want to create new nodes and nids or use the current ones.
+
Make sure you set up the CCK date field to have both a 'From Date' and a 'To Date'. If your events have event-specific timezones, make sure the CCK date field is set up to use the date's timezone.
+
Go to Admin >> Content management >> Date Import/Export >> Import >> Events and select 'Events' as the content type to import from and your new content type as the type to import to. Only content types that have date fields will appear in the list of available content types.
+
If you have added the new date fields to the current content type, be sure to select the option to NOT delete the old node after the import. If you have created a new content type, you will probably want to delete the old nodes.
+
You can select the number of items to import and the starting nid (import will be done in ascending nid order). Use that to import a single node as a test to be sure the results are what you want.
+
Once your nodes seem to be importing correctly, go ahead and import more of them. You may want to do them in batches to keep the server from timing out.
+
\ No newline at end of file
diff --git a/sites/all/modules/date/help/date-create.html b/sites/all/modules/date/help/date-create.html
new file mode 100644
index 0000000..11ac97d
--- /dev/null
+++ b/sites/all/modules/date/help/date-create.html
@@ -0,0 +1,21 @@
+
The DateTime object is defined in PHP versions 5.2 and greater. Full documentation can be found at php.net/datetime.
+
+
PHP's print_r(), Devel module's dpm(), and similar functions and most debuggers are not able to show the properties of DateTime objects. The date_format() function provides a good alternate method to debug DateTime objects. An example of its usage follows, including some common DateTime manipulation functions;
+
+
+
+ <?php // Create a DateTime object for 11 November 2008, 5pm, Chicago time. $date=date_create('2008-11-11 17:00:00',timezone_open('America/Chicago'));
+ // Find out what time it is in New York. date_timezone_set($date,timezone_open('America/New_York'));
+ // Now move it ahead to the following Tuesday. date_modify($date,'+1 Tuesday');
+ // Print out the result. printdate_format($date,'l r');
+ // "Tuesday Tue, 18 Nov 2008 18:00:00 -0500"
+ ?>
+
+
+
+The Date API provides a helper function, date_make_date($string, $timezone, $type),
+where $string is a unixtimestamp, an ISO date, or a string like YYYY-MM-DD HH:MM:SS,
+$timezone is the name of the timezone this date is in, and $type is the type
+of date it is (DATE_UNIX, DATE_ISO, or DATE_DATETIME). It creates and return
+a date object set to the right date and timezone.
+
diff --git a/sites/all/modules/date/help/date-display.html b/sites/all/modules/date/help/date-display.html
new file mode 100644
index 0000000..aff5165
--- /dev/null
+++ b/sites/all/modules/date/help/date-display.html
@@ -0,0 +1,59 @@
+
The date field can be displayed, or formatted, several ways, some configurable in the date settings, others that are automatically provided as options.
+
You'll see these formatters as options on the 'Display fields' screen and when you add the fields to Views. You can also use these formatters in custom code by doing something like:
In many places you can further control the way multiple value dates will be displayed with formatter settings. The formatter settings look like:
+
+
+
+
+
+
+
+
+
+ Show value(s)
+
+
+
+ starting from
+
+
+ ending on
+
+
+
+
+
+
The number of values should be a numeric value, or blank to show all dates that match your other options.
+'Starting from' and 'Ending on' can be a fixed dates in ISO format (like 2009-03-03T10:30:00) or relative times like 'now' or 'now +1 day'.
+
+
+
Formats and Format Types
+
Formatter options include:
+
+
default
+
The main way to display this date, configured in the Date settings, defaults to the site short format.
+
short
+
The site short format.
+
medium
+
The site medium format.
+
long
+
The site long format.
+
time
+
Display the date time only, using the time format in the default display.
+
time_timezone
+
Display the date time and timezone, using the time format in the default display.
+
iso
+
Display the date in the standard ISO format of YYYY-MM-DDTHH:MM:SS.
+
ical
+
Display the date in the standard iCal format of YYYYMMDDTHHMMSS.
+
timestamp
+
Display the date as the Unix timestamp value.
+
format_interval
+
Display the date as 'XX days, XX hours ago' or 'XX months, XX days from now'.
+
+
To set up custom formats and formatters, go to admin/settings/date-time/formats. You can either use a pre-configured display format, or create your own formatters and formats. Define a php date format string like 'm-d-Y H:i' (see http://php.net/date for more details on custom format strings.)
\ No newline at end of file
diff --git a/sites/all/modules/date/help/date-filter.html b/sites/all/modules/date/help/date-filter.html
new file mode 100644
index 0000000..407fdd5
--- /dev/null
+++ b/sites/all/modules/date/help/date-filter.html
@@ -0,0 +1 @@
+
The Date API provides a generic Date filter that can filter on any Views date field.
diff --git a/sites/all/modules/date/help/date-php4.html b/sites/all/modules/date/help/date-php4.html
new file mode 100644
index 0000000..b305d79
--- /dev/null
+++ b/sites/all/modules/date/help/date-php4.html
@@ -0,0 +1,41 @@
+
Note: The Date API is designed to use the new PHP date and timezone functions that are available in PHP 5.2 and above. If you're using an earlier version of PHP, you'll need to enable the Date PHP4 module which provides some wrapper code to emulate those functions. The wrapper code is slower and less efficient than the native date functions, so if at all possible, you will want to run on a server that uses PHP 5.2 or higher for the best performance. Some distros, like Red Hat, use PHP 5.1 instead. See Installing PHP 5.2 on RedHat for ideas on how to update that.
+
+
PHP 4 substitutions for the PHP 5 date functions are supplied if the Date PHP4 module is enabled. Use the PHP 5
+functions in your code as they would normally be used and the PHP 4
+alternatives will be automatically be substituted in when needed.
+
+
+You cannot do everything with these functions that can be done in PHP 5, but
+you can create dates, find timezone offsets, and format the results.
+Timezone handling uses native PHP 5 functions when available and degrades
+automatically for PHP 4 to use substitutions like those
+provided in previous versions of the Date and Event modules.
+
+
+Read the doxygen documentation in this module for more information
+about using the functions in ways that will work in PHP 4.
+
+
+The following functions are emulated in PHP4:
+
+
+
+date_create()
+
+date_date_set()
+
+date_format()
+
+date_offset_get()
+
+date_timezone_set()
+
+timezone_abbreviations_list()
+
+timezone_identifiers_list()
+
+timezone_offset_get()
+
+timezone_open()
+
+
diff --git a/sites/all/modules/date/help/date-repeat-form.html b/sites/all/modules/date/help/date-repeat-form.html
new file mode 100644
index 0000000..2d75686
--- /dev/null
+++ b/sites/all/modules/date/help/date-repeat-form.html
@@ -0,0 +1,8 @@
+
Dates will match any selection within the same box [January OR June]. When more than one box has criteria selected, all of them are combined to create repeats [[January OR June] AND [Day 1 OR Day 15]]. Positive numbers count from the beginning of the period. Negative numbers count from the end of the period, i.e. -1 is the last, -2 is the next to last, etc.
+
+
If you select 'Every Year' above, and 'March' from 'Month' and '1' and '15' from 'Day of Month' in the Advanced options you will be selecting the 1st and 15th days of March of every year.
+
If you select 'Every other Month' above, and 'Second Tuesday' in the Advanced options you will be selecting the second Tuesday of every other month.
+
If you select 'Every Year' above, and 'Second Tuesday' in the Advanced options you will be selecting the second Tuesday of every year.
+
If you select 'Every Month' above, and 'January' and 'June' and 'First Saturday' in the Advanced options, you will be selecting the first Saturday in January or June.
+
If you select 'Every Month' above, and '-1' from 'Day of Month' in the Advanced options you will be selecting the last day of every month.
+
\ No newline at end of file
diff --git a/sites/all/modules/date/help/date-timezones.html b/sites/all/modules/date/help/date-timezones.html
new file mode 100644
index 0000000..c33c791
--- /dev/null
+++ b/sites/all/modules/date/help/date-timezones.html
@@ -0,0 +1,447 @@
+
Creating a timezone form item using Date API
+
+This is simple. Just use the 'date_timezone' type, which is provided by date_api.module.
+
+
+<?php
+ $form['timezone'] = array(
+ '#type' => 'date_timezone',
+ '#default_value' => $timezone,
+ '#description' => "Select a timezone if all the events will happen in the same place. Select that place's timezone",
+ );
+?>
+
+
Converting to and from UTC
+
+In the new system you just need to know the timezone name and either the UTC or local time. We store the UTC time and the timezone name in the database (in two separate fields). We retrieve that data and do:
+
+
+<?php
+$date = the UTC value from the database
+$local_zone = the name of the local timezone
+$type = the type of date value, DATE_DATETIME, DATE_ISO, or DATE_UNIX
+
+$date = date_make_date($date, 'UTC', $type);
+date_timezone_set($date, timezone_open($local_zone);
+
+$date now contains the local value of the date.
+Output it like:
+
+print date_format_date($date, 'custom', 'm/d/Y H:i');
+?>
+
+
+To convert a local date back to UTC to store it in the database, do:
+
+
+<?php
+$date = local date value
+$local_zone = the name of the local timezone
+$type = the type of date value, DATE_DATETIME, DATE_ISO, or DATE_UNIX
+
+$date = date_make_date($date, $local_zone, $type);
+date_timezone_set($date, timezone_open('UTC');
+
+$date now contains the UTC value of the date.
+Output it like:
+
+print date_format_date($date, 'custom', 'm/d/Y H:i');
+?>
+
+
+
Use of timezone abbreviations
+
+The API doesn't handle timezone abbreviations at all, there's no way to do it right because they are not unique (EST could be Eastern Standard Time or European Summer Time). We need the full, undeprecated timezone name, which looks like 'America/Chicago'. It is comprised of the name of the continent and the major city in the timezone. Older names like 'US/Central' are deprecated because the area names change, but city names rarely do. Some good info about timezones is at http://en.wikipedia.org/wiki/Zoneinfo.
+
+Also, we do not use spaces in the timezone names, so we use America/New_York, not America/New York. The PHP 5.2 date functions and MYSQL native timezone handling all expect names without spaces in them to work correctly.
+
+You can use the php function timezone_name_from_abbr() to try to translate to and from abbreviations, but it's not entirely reliable, as noted above. If we have the current offset and we know if it's currently daylight savings time or not, you can combine that with the abbreviation to get the timezone name, but that's a lot of 'if's.
+
+
Timezone Names
+
+The complete list of allowed, undeprecated timezone names is:
+
\ No newline at end of file
diff --git a/sites/all/modules/date/help/date-types.html b/sites/all/modules/date/help/date-types.html
new file mode 100644
index 0000000..794073e
--- /dev/null
+++ b/sites/all/modules/date/help/date-types.html
@@ -0,0 +1,39 @@
+
Date Fields
+
The CCK Date field uses the Date API to create date fields and widgets.
+
You have a choice of creating an ISO date or a unix timestamp. If you are porting information from another application you may want to create a field using a type that matches the source data. Some advantages and disadvantages of each include:
+
+
Datestamp (Unix Timestamp)
+
+
Stores the date as an integer.
+
Takes up less room in the database because it's smaller.
+
Often easier to use for date calculations because you can increase or decrease it just by adding or subtracting seconds.
+
It is the format used by php date functions.
+
It must be filled with a complete date -- year, month, day, hour, minute, second, so you sometimes have to arbitrarily set some of these values even if they are not applicable.
+
+
+
Date (ISO Date)
+
+
Stores the date in an ISO format (YYYY-MM-DDTHH:MM:SS).
+
The data is in a human-readable form.
+
You can use it for incomplete dates, i.e. only a year or only a year and a month, and pad the other values with zeros, so it does not appear to be any more precise than it really is.
+
It is a format that is internationally-recognized, and it is used as-is on many web sites and in many applications.
+
+
+
Datetime
+
+
Stores the date in the database's native date format (YYYY-MM-DD HH:MM:SS).
+
The data is in a human-readable form.
+
You can use it for incomplete dates, i.e. only a year or only a year and a month, and pad the other values with zeros, so it does not appear to be any more precise than it really is.
+
It can take advantage of the database's date handling functions without any conversion.
+
+
+
Date Widgets
+
There are several widgets to choose from to control how users can enter data for this field.
+
+
Text Field
The Text Field date widget uses a custom format set in the field settings, like '31.12.2008'. As a fallback the widget will try to accept input allowed by the php strtotime function. This allows the user to type a date in in many natural formats, like 'March 31, 1980'.
+There are limitations to strtotime, so setting a custom format is more reliable. The strtotime function will assume date shortcuts are in American format (MM/DD/YY), and strtotime will not work for dates prior to 1970.
+
+
Select List
The Select List date widget presents users with a drop-down list or textfield for each part of the date (year, month, day, hour, etc.). The whole selector is collapsed onto a single line using css (except for the timezone selector, if date-specific timezones are collected). The selector is highly configurable and you can set it up to use 5, 10, or 15 minute increments for minutes and seconds, or make some parts of the selector use textfields instead of drop-downs, useful to allow any year without creating a huge drop-down selector.
+
jQuery Pop-up Calendar
The Javascript Pop-up Calendar is offered as an input alternative if the Date Popup module is installed. The date is split into date and time fields, and the date field uses a jQuery popup calendar and the time field uses a jQuery timeselector widget that only allows valid time input.
+
+
If you have the Date Repeat module enabled, you will also see options for each of those widgets that include a repeat options selection form that will allow the user to choose values like 'Every week' or 'The last Tuesday'.
\ No newline at end of file
diff --git a/sites/all/modules/date/help/date-views-dates.html b/sites/all/modules/date/help/date-views-dates.html
new file mode 100644
index 0000000..67f3c4b
--- /dev/null
+++ b/sites/all/modules/date/help/date-views-dates.html
@@ -0,0 +1,45 @@
+
Custom modules and add their own dates to the list the Date API Views filter and Date API Views argument can handle. See the following example for the way that core dates have been added:
+
+/**
+ * Implementation of hook_date_api_fields().
+ * on behalf of core fields.
+ *
+ * All modules that create custom fields that use the
+ * 'views_handler_field_date' handler can provide
+ * additional information here about the type of
+ * date they create so the date can be used by
+ * the Date API views date argument and date filter.
+ */
+function date_api_date_api_fields($field) {
+ $values = array(
+ // The type of date: DATE_UNIX, DATE_ISO, DATE_DATETIME.
+ 'sql_type' => DATE_UNIX,
+ // Timezone handling options: 'none', 'site', 'date', 'utc'.
+ 'tz_handling' => 'site',
+ // Needed only for dates that use 'date' tz_handling.
+ 'timezone_field' => '',
+ // Needed only for dates that use 'date' tz_handling.
+ 'offset_field' => '',
+ // Array of "table.field" values for related fields that should be
+ // loaded automatically in the Views SQL.
+ 'related_fields' => array(),
+ // Granularity of this date field's db data.
+ 'granularity' => array('year', 'month', 'day', 'hour', 'minute', 'second'),
+ );
+
+ switch ($field) {
+ case 'users.created':
+ case 'users.access':
+ case 'users.login':
+ case 'node.created':
+ case 'node.changed':
+ case 'node_revisions.timestamp':
+ case 'files.timestamp':
+ case 'node_counter.timestamp':
+ case 'accesslog.timestamp':
+ case 'comments.timestamp':
+ case 'node_comment_statistics.last_comment_timestamp':
+ return $values;
+ }
+}
+
\ No newline at end of file
diff --git a/sites/all/modules/date/help/date-views.html b/sites/all/modules/date/help/date-views.html
new file mode 100644
index 0000000..e69de29
diff --git a/sites/all/modules/date/help/date.html b/sites/all/modules/date/help/date.html
new file mode 100644
index 0000000..834ffa1
--- /dev/null
+++ b/sites/all/modules/date/help/date.html
@@ -0,0 +1,2 @@
+
Settings are used to override some values of the view.
+
The primary setting that is useful here is a setting for 'block_identifier'. The view's block_identifier is used to control individual instances of regular and embedded views that contain date navigation so that they move separately or together. All views that use the same identifier will move together.
+All views that use different identifiers will move independently. The identifier will show up in the url as a querystring, like node/275?mini=calendar/2008-10.
+
This will embed the first block view of the view and use 'mini' as an identifier, set to show the month view for July 2008.
+
diff --git a/sites/all/modules/date/help/form-elements.html b/sites/all/modules/date/help/form-elements.html
new file mode 100644
index 0000000..6c61289
--- /dev/null
+++ b/sites/all/modules/date/help/form-elements.html
@@ -0,0 +1,50 @@
+
Usage example of date elements within forms
+
+* Enable the Date API module (you might want to add a dependency in the .info file of your module).
+* Date API uses hook_elements() to create custom form types. You can check the file date_api_elements.inc for the list of form types available, and for other configuration options.
+
+
+Adding a date form element is then easy.
+
+<?php
+/**
+ * Your form builder.
+ */
+function mymodule_form($form_state) {
+ $form = array();
+
+ // [...snip...] add many fields to your form
+
+ // Creating the date/time element starts here
+
+ // Provide a default date in the format YYYY-MM-DD HH:MM:SS.
+ $date = '2008-12-31 00:00:00';
+
+ // Provide a format using regular PHP format parts (see documentation on php.net).
+ // If you're using a date_select, the format will control the order of the date parts in the selector,
+ // rearrange them any way you like. Parts left out of the format will not be displayed to the user.
+ $format = 'Y-m-d H:i';
+
+ $form['date2'] = array(
+ '#type' => 'date_select', // types 'date_text' and 'date_timezone' are also supported. See .inc file.
+ '#title' => 'select a date',
+ '#default_value' => $date,
+ '#date_format' => $format,
+ '#date_label_position' => 'within', // See other available attributes and what they do in date_api_elements.inc
+ '#date_timezone' => 'America/Chicago', // Optional, if your date has a timezone other than the site timezone.
+ '#date_increment' => 15, // Optional, used by the date_select and date_popup elements to increment minutes and seconds.
+ '#date_year_range' => '-3:+3', // Optional, used to set the year range (back 3 years and forward 3 years is the default).
+ );
+
+ // [...snip...] more fields, including the 'submit' button.
+
+ return $form;
+}
+?>
+
+
These are self-validating elements, you shouldn't need to do anything except include them in your form. You pass them parameters for the timezone, format, and a default value in the format YYYY-MM-DD HH:MM:SS, and it will convert your input into the format the element wants, split the date and time into different fields as needed, then accept and validate the user input and convert it back into a string in the same format you originally provided (YYYY-MM-DD HH:MM:SS). So you pass it a string and it will pass back a string by the time you get to your own validation function.
+
+You are responsible for doing your own timezone conversion, the element uses the timezone just so it can create a date object with the right timezone for doing its formatting. So if you need to do timezone conversion, you pull your UTC date out of the database and convert it to a local date, pass that value to the Date element, then take what it returns and convert it back to UTC and store it in the database again.
+
+If the Date Popup module is enabled, a date_popup element can be used. It works like the other elements, but splits the date and time into separate parts. You control whether it uses date or date and time by the format you supply in #date_format. If you don't have any time parts in the format, you won't get a time element. Note that the jquery widget (the 'date' part of the popup) can only accept a limited number of formats, things like Y-m-d or m/d/Y or d.m.Y.
+
diff --git a/sites/all/modules/date/help/new-features.html b/sites/all/modules/date/help/new-features.html
new file mode 100644
index 0000000..c0afa74
--- /dev/null
+++ b/sites/all/modules/date/help/new-features.html
@@ -0,0 +1,11 @@
+
+
The Date API now uses PHP 5.2 date functions for better date and timezone handling (and has PHP 4 emulations for those functions so the module will work in PHP4). Although the code will work with PHP 4, it is significantly faster and more efficient under PHP 5.2 or higher, so PHP 5.2 is highly recommended.
+
The database query handling has been completely re-worked to take advantage of database timezone handling when available, with a fallback to the older and less reliable method of using offsets to do timezone adjustments.
+
No more need for the adodb date library, historical dates earlier than 1970 and later than 2038 are handled without any external code.
+
iCal integration is greatly improved, an iCal parser can parse events, alarms, most types of dates and timezones, duration, repeat rules, and more.
+
The Date API creates date elements that can be used by any module, including 'date_select', 'date_textfield', and 'date_timezone'.
+
A new Date Timezone module overrides the site and user timezone selectors to allow you to select a timezone name instead of a timezone offset, and that stored name is used to properly adjust date values. It also detects the user's timezone name automatically and updates the user record with that name.
+
A new Date Popup module creates a jQuery popup calendar date picker and time picker, and the element is available to other modules as a form type of 'date_popup'.
+
The Date module now has lots of new ways to define default values -- you can set a the default to 'blank', 'now', or 'relative', where relative is something like '+90 days'. The To date has a separate default value, which can be the same as the From date or do something different.
+
A Date Repeat API module has been added which can be used by any other module. The CCK Date module uses it to allow you to select 'repeating' as a type of multiple date, present the user with a form to select the repeat rules for their date, and then create all the multiple values that match those rules.
+
\ No newline at end of file
diff --git a/sites/all/modules/date/help/overview.html b/sites/all/modules/date/help/overview.html
new file mode 100644
index 0000000..4f4646f
--- /dev/null
+++ b/sites/all/modules/date/help/overview.html
@@ -0,0 +1,2 @@
+
The date module defines a highly configurable date/time field type for the content module and a date API that can be used by other applications.
+
diff --git a/sites/all/modules/date/images/calendar.png b/sites/all/modules/date/images/calendar.png
new file mode 100644
index 0000000000000000000000000000000000000000..9d40d4c6faf2b3831919865cf6bc20bee7d3d705
GIT binary patch
literal 440
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5
z;QX|b^2DN42FH~Aq*MjZ+{E4wj_uq^eGd_O%`4=eq_upS2|L@;JH=Z84{_OXkzmMO2e)skJr|-Xjq7Pqx
zy8r6qk6*u^zWeg-%lE5K-|o5c_}kB4Uw{7Idf~yj2d{qq{&V}qhcDlMJ$d)#*}E?<
zKYhFT{QdgVcVB+|cH;Jn-+%sm`u_9(|Nky){@(^VNw*}(FBr%r8Zaz<&;1vuvCh-Q
zF{I*FPtS3_Lk>Kw?WJ>^UhHj;`~H7F|NA0EL3TI)X*So4_c5+ztLG@ceX)K*oa8;t
zZG79`1ui|~r^EeCR``m+Mym}w4DL_qlrM>&GuC1QifMHS>2k)Uifk{A@FnGH9xvX!PdIprF*GqSmUR-KnYF
zrK#PirQ4%tI6>dA*Vt^5k;!xmtC?0db8Q{w+Bq(8^<3iRyV%EXg^&MZOWV~!p=*M}
zHbg`p$S+*b&~U7#abIiOh5iYbXUw`bd+znw^KLI*dVlr02W!{w+qduG#?6m6Z+p6P
z_tV{bPMtdS;?R-Dk01a4|DS array(
+ 'path' => drupal_get_path('module', 'date_api') .'/includes',
+ ),
+ 'handlers' => array(
+ 'date_api_argument_handler' => array(
+ 'parent' => 'views_handler_argument_date',
+ ),
+ 'date_api_filter_handler' => array(
+ 'parent' => 'views_handler_filter_numeric',
+ ),
+ ),
+ );
+}
+
+/**
+ * Implementation of hook_views_plugins().
+ */
+function date_api_views_plugins() {
+ $path = drupal_get_path('module', 'date_api');
+ $views_path = drupal_get_path('module', 'views');
+ require_once "./$path/theme/theme.inc";
+ return array(
+ 'module' => 'date_api', // This just tells our themes are elsewhere.
+ 'display' => array(
+ // Parents are not really displays, just needed so the files can
+ // be included.
+ 'parent' => array(
+ 'no ui' => TRUE,
+ 'handler' => 'views_plugin_display',
+ 'path' => "$views_path/plugins",
+ 'parent' => '',
+ ),
+ 'attachment' => array(
+ 'no ui' => TRUE,
+ 'handler' => 'views_plugin_display_attachment',
+ 'path' => "$views_path/plugins",
+ 'parent' => 'parent',
+ ),
+ // Display plugin for date navigation.
+ 'date_nav' => array(
+ 'title' => t('Date browser'),
+ 'help' => t('Date back/next navigation to attach to other displays. Requires the Date argument.'),
+ 'handler' => 'date_plugin_display_attachment',
+ 'parent' => 'attachment',
+ 'path' => "$path/includes",
+ 'theme' => 'views_view',
+ 'use ajax' => TRUE,
+ 'admin' => t('Date browser'),
+ 'help topic' => 'date-browser',
+ ),
+ ),
+ 'style' => array(
+ 'parent' => array(
+ // this isn't really a display but is necessary so the file can
+ // be included.
+ 'no ui' => TRUE,
+ 'handler' => 'views_plugin_style',
+ 'path' => "$views_path/plugins",
+ 'theme file' => 'theme.inc',
+ 'theme path' => "$views_path/theme",
+ 'parent' => '',
+ ),
+ 'date_nav' => array(
+ 'title' => t('Date browser style'),
+ 'help' => t('Creates back/next navigation.'),
+ 'handler' => 'date_navigation_plugin_style',
+ 'path' => "$path/includes",
+ 'parent' => 'parent',
+ 'theme' => 'date_navigation',
+ 'theme file' => 'theme.inc',
+ 'theme path' => "$path/theme",
+ 'uses row plugin' => FALSE,
+ 'uses fields' => FALSE,
+ 'uses options' => TRUE,
+ 'type' => 'date_nav',
+ 'even empty' => TRUE,
+ ),
+ ),
+ );
+}
+
+/**
+ * Implementation of hook_views_data().
+ */
+function date_api_views_data() {
+ $data = array();
+
+ $tables = module_invoke_all('date_api_tables');
+
+ foreach ($tables as $base_table) {
+ // The flexible date argument.
+ $data[$base_table]['date_argument'] = array(
+ 'group' => t('Date'),
+ 'title' => t('Date (!base_table)', array('!base_table' => $base_table)),
+ 'help' => t('Filter any Views !base_table date field by a date argument, using any common ISO date/period format (i.e. YYYY, YYYY-MM, YYYY-MM-DD, YYYY-W99, YYYY-MM-DD--P3M, P90D, etc).', array('!base_table' => $base_table)),
+ 'argument' => array(
+ 'handler' => 'date_api_argument_handler',
+ 'empty field name' => t('Undated'),
+ 'base' => $base_table,
+ ),
+ );
+ // The flexible date filter.
+ $data[$base_table]['date_filter'] = array(
+ 'group' => t('Date'),
+ 'title' => t('Date (!base_table)', array('!base_table' => $base_table)),
+ 'help' => t('Filter any Views !base_table date field.', array('!base_table' => $base_table)),
+ 'filter' => array(
+ 'handler' => 'date_api_filter_handler',
+ 'empty field name' => t('Undated'),
+ 'base' => $base_table,
+ ),
+ );
+ }
+ return $data;
+}
+
+/**
+ * Identify all potential date/timestamp fields and cache the data.
+ */
+function date_api_fields($base = 'node', $reset = FALSE) {
+ static $fields = array();
+ $empty = array('name' => array(), 'alias' => array());
+ require_once('./'. drupal_get_path('module', 'date_api') .'/includes/date_api_fields.inc');
+ if (empty($fields[$base]) || $reset) {
+ $cid = 'date_api_fields_'. $base;
+ if (!$reset && $cached = cache_get($cid, 'cache_views')) {
+ $fields[$base] = $cached->data;
+ }
+ else {
+ $fields[$base] = _date_api_fields($base);
+ }
+ }
+ // Make sure that empty values will be arrays in he expected format.
+ return !empty($fields) && !empty($fields[$base]) ? $fields[$base] : $empty;
+}
+
+/**
+ * Central function for setting up the right timezone values
+ * in the SQL date handler.
+ *
+ * The date handler will use this information to decide if the
+ * database value needs a timezone conversion.
+ *
+ * In Views, we will always be comparing to a local date value,
+ * so the goal is to convert the database value to the right
+ * value to compare to the local value.
+ */
+function date_views_set_timezone(&$date_handler, &$view, $field) {
+ $tz_handling = $field['tz_handling'];
+ switch ($tz_handling) {
+ case 'date' :
+ $date_handler->db_timezone = 'UTC';
+ $date_handler->local_timezone_field = $field['timezone_field'];
+ $date_handler->offset_field = $field['offset_field'];
+ break;
+ case 'none':
+ $date_handler->db_timezone = date_default_timezone_name();
+ $date_handler->local_timezone = date_default_timezone_name();
+ break;
+ case 'utc':
+ $date_handler->db_timezone = 'UTC';
+ $date_handler->local_timezone = 'UTC';
+ break;
+ default :
+ $date_handler->db_timezone = 'UTC';
+ $date_handler->local_timezone = date_default_timezone_name();
+ break;
+ }
+}
+
+function date_views_querystring($view, $extra_params = array()) {
+ $query_params = array_merge($_GET, $extra_params);
+ // Allow NULL params to be removed from the query string.
+ foreach ($extra_params AS $key => $value) {
+ if (!isset($value)) {
+ unset($query_params[$key]);
+ }
+ }
+ // Filter the special "q" and "view" variables out of the query string.
+ $exclude = array('q');
+ // If we don't explicitly add a value for "view", filter it out.
+ if (empty($extra_params['view'])) {
+ $exclude[] = 'view';
+ }
+ $query = drupal_query_string_encode($query_params, $exclude);
+ // To prevent an empty query string from adding a "?" on to the end of a URL,
+ // we return NULL.
+ return !empty($query) ? $query : NULL;
+}
+
+/**
+ * Identify the base url of the page,
+ * needed when the calendar is embedded so we
+ * don't set the url to the calendar url.
+ */
+function date_views_page_url($view) {
+ if ($view->build_type == 'page') {
+ return date_views_real_url($view, $view->date_info->real_args);
+ }
+ else {
+ $block_identifier = isset($view->date_info->block_identifier) ? $view->date_info->block_identifier : 'mini';
+ return url($_GET['q'], date_views_querystring($view, array($block_identifier => NULL)), NULL, TRUE);
+ }
+}
+
+/**
+ * Figure out what the URL of the calendar view we're currently looking at is.
+ */
+function date_views_real_url($view, $args) {
+ if (empty($args)) {
+ return $view->date_info->url;
+ }
+ // Add non-calendar arguments to the base url.
+ $parts = explode('/', $view->date_info->url);
+ $bump = 0;
+ foreach ($parts as $delta => $part) {
+ // If one of the args is buried in the url, add it here and adjust
+ // the delta values we'll compare the calendar arg positions to.
+ if (drupal_substr($part, 0, 1) == '$') {
+ $parts[$delta] = array_shift($args);
+ $bump++;
+ }
+ }
+ foreach ($args as $delta => $arg) {
+ if (!in_array($delta + $bump, calendar_arg_positions($view)) && !empty($arg)) {
+ array_push($parts, $arg);
+ }
+ }
+ return implode('/', $parts);
+}
diff --git a/sites/all/modules/date/includes/date_api.views_default.inc b/sites/all/modules/date/includes/date_api.views_default.inc
new file mode 100644
index 0000000..1a97895
--- /dev/null
+++ b/sites/all/modules/date/includes/date_api.views_default.inc
@@ -0,0 +1,98 @@
+name = 'date_browser';
+$view->description = 'Browse through nodes by year, month, day, or week. Date browser attachment adds back/next navigation to the top of the page.';
+$view->tag = 'Date';
+$view->view_php = '';
+$view->base_table = 'node';
+$view->is_cacheable = FALSE;
+$view->api_version = 2;
+$view->disabled = TRUE; /* Edit this to true to make a default view disabled initially */
+$handler = $view->new_display('default', 'Defaults', 'default');
+$handler->override_option('arguments', array(
+ 'date_argument' => array(
+ 'default_action' => 'default',
+ 'style_plugin' => 'default_summary',
+ 'style_options' => array(),
+ 'wildcard' => 'all',
+ 'wildcard_substitution' => 'All',
+ 'title' => '',
+ 'default_argument_type' => 'date',
+ 'default_argument' => '',
+ 'validate_type' => 'none',
+ 'validate_fail' => 'not found',
+ 'date_fields' => array(
+ 'node.changed' => 'node.changed',
+ ),
+ 'year_range' => '-3:+3',
+ 'date_method' => 'OR',
+ 'granularity' => 'month',
+ 'id' => 'date_argument',
+ 'table' => 'node',
+ 'field' => 'date_argument',
+ 'relationship' => 'none',
+ 'default_argument_user' => 0,
+ 'default_argument_fixed' => '',
+ 'default_argument_php' => '',
+ 'validate_argument_node_type' => array(),
+ 'validate_argument_node_access' => 0,
+ 'validate_argument_nid_type' => 'nid',
+ 'validate_argument_vocabulary' => array(),
+ 'validate_argument_type' => 'tid',
+ 'validate_argument_php' => '',
+ 'default_options_div_prefix' => '',
+ 'validate_argument_signup_status' => 'any',
+ 'validate_argument_signup_node_access' => 0,
+ 'override' => array(
+ 'button' => 'Override',
+ ),
+ ),
+));
+$handler->override_option('access', array(
+ 'type' => 'none',
+ 'role' => array(),
+ 'perm' => '',
+));
+$handler->override_option('items_per_page', 0);
+$handler->override_option('use_pager', '1');
+$handler->override_option('row_plugin', 'node');
+$handler->override_option('row_options', array(
+ 'teaser' => 1,
+ 'links' => 1,
+ 'comments' => 0,
+));
+$handler = $view->new_display('page', 'Page', 'page');
+$handler->override_option('path', 'date-browser');
+$handler->override_option('menu', array(
+ 'type' => 'none',
+ 'title' => '',
+ 'weight' => 0,
+ 'name' => 'navigation',
+));
+$handler->override_option('tab_options', array(
+ 'type' => 'none',
+ 'title' => '',
+ 'weight' => 0,
+));
+$handler = $view->new_display('date_nav', 'Date browser', 'date_nav_1');
+$handler->override_option('style_plugin', 'date_nav');
+$handler->override_option('row_plugin', 'fields');
+$handler->override_option('row_options', array());
+$handler->override_option('attachment_position', 'before');
+$handler->override_option('inherit_arguments', TRUE);
+$handler->override_option('inherit_exposed_filters', TRUE);
+$handler->override_option('displays', array(
+ 'page' => 'page',
+ 'default' => 0,
+));
+
+ $views[$view->name] = $view;
+ return $views;
+}
\ No newline at end of file
diff --git a/sites/all/modules/date/includes/date_api_argument_handler.inc b/sites/all/modules/date/includes/date_api_argument_handler.inc
new file mode 100644
index 0000000..37c5a53
--- /dev/null
+++ b/sites/all/modules/date/includes/date_api_argument_handler.inc
@@ -0,0 +1,398 @@
+date_handler = new date_sql_handler();
+ $this->date_handler->construct();
+ }
+
+ /**
+ * Get granularity and use it to create the formula and a format
+ * for the results.
+ */
+ function init(&$view, $options) {
+ parent::init($view, $options);
+
+ // Identify the type of display we're using.
+ $this->display_handler = $view->display_handler->definition['handler'];
+
+ // Add a date handler to the display.
+ $date_handler = $this->date_handler;
+ $date_handler->granularity = $this->options['granularity'];
+ $this->format = $date_handler->views_formats($date_handler->granularity, 'display');
+ $this->sql_format = $date_handler->views_formats($date_handler->granularity, 'sql');
+
+ if (empty($this->view->date_info)) $this->view->date_info = new stdClass();
+
+ // Set the view range, do this only if not already set in case there are multiple date arguments.
+ if (empty($this->view->date_info->min_allowed_year)) {
+ $range = date_range_years($this->options['year_range']);
+ $this->view->date_info->min_allowed_year = !empty($range) && is_array($range) ? $range[0] : variable_get('min_allowed_year', 100);
+ $this->view->date_info->max_allowed_year = !empty($range) && is_array($range) ? $range[1] : variable_get('max_allowed_year', 4000);
+ }
+ if (empty($this->view->date_info->date_fields)) {
+ $this->view->date_info->date_fields = array();
+ }
+ $this->view->date_info->date_fields = array_merge($this->view->date_info->date_fields, $this->options['date_fields']);
+ }
+
+ /**
+ * Default value for the date_fields option.
+ */
+ function option_definition() {
+ $options = parent::option_definition();
+ $options['date_fields'] = array('default' => array());
+ $options['year_range'] = array('default' => '-3:+3', 'export' => 'export_plugin');
+ $options['date_method'] = array('default' => 'OR', 'export' => 'export_plugin');
+ $options['granularity'] = array('default' => 'month', 'export' => 'export_plugin');
+ $options['default_argument_type'] = array('default' => 'date', 'export' => 'export_plugin');
+ return $options;
+ }
+
+ /**
+ * Make sure our custom options get exported.
+ * Handle the options we know about, pass the rest to the parent plugin.
+ */
+ function export_plugin($indent, $prefix, $storage, $option, $definition, $parents) {
+ $output = '';
+ if (in_array($option, array('year_range', 'granularity', 'default_argument_type', 'date_method'))) {
+ $name = $this->options[$option];
+ $output .= $indent . $prefix . "['$option'] = '$name';\n";
+ return $output;
+ }
+ return parent::export_plugin($indent, $prefix, $storage, $option, $definition, $parents);
+ }
+
+ /**
+ * Add a form element to select date_fields for this argument.
+ */
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+ $options = $this->date_handler->date_parts();
+ unset($options['second'], $options['minute']);
+ $options += array('week' => date_t('Week', 'datetime'));
+ $form['granularity'] = array(
+ '#title' => t('Granularity'),
+ '#type' => 'radios',
+ '#options' => $options,
+ '#default_value' => $this->options['granularity'],
+ '#multiple' => TRUE,
+ '#description' => t("Select the type of date value to be used in defaults, summaries, and navigation. For example, a granularity of 'month' will set the default date to the current month, summarize by month in summary views, and link to the next and previous month when using date navigation."),
+ );
+
+ $form['year_range'] = array(
+ '#title' => t('Date year range'),
+ '#type' => 'textfield',
+ '#default_value' => $this->options['year_range'],
+ '#description' => t("Set the allowable minimum and maximum year range for this argument, either a -X:+X offset from the current year, like '-3:+3' or an absolute minimum and maximum year, like '2005:2010'. When the argument is set to a date outside the range, the page will be returned as 'Page not found (404)'."),
+ );
+
+ $fields = date_api_fields($this->definition['base']);
+ $options = array();
+ foreach ($fields['name'] as $name => $field) {
+ $options[$name] = $field['label'];
+ }
+
+ // If this argument was added as a CCK field argument and no other date field
+ // has been chosen, update the default with the right date.
+ if (empty($this->options['date_fields']) && $this->field != 'date_argument') {
+ $this->options['date_fields'] = array($this->table .'.'. $this->field);
+ }
+
+ $form['date_fields'] = array(
+ '#title' => t('Date field(s)'),
+ '#type' => 'checkboxes',
+ '#options' => $options,
+ '#default_value' => $this->options['date_fields'],
+ '#multiple' => TRUE,
+ '#description' => t("Select one or more date fields to filter with this argument. Do not select both the 'From date' and 'To date' for CCK date fields, only one of them is needed."),
+ );
+ $form['date_method'] = array(
+ '#title' => t('Method'),
+ '#type' => 'radios',
+ '#options' => array('OR' => t('OR'), 'AND' => t('AND')),
+ '#default_value' => $this->options['date_method'],
+ '#description' => t('Method of handling multiple date fields in the same query. Return items that have any matching date field (date = field_1 OR field_2), or only those with matches in all selected date fields (date = field_1 AND field_2).'),
+ );
+
+ }
+
+ function options_validate($form, &$form_state) {
+ // It is very important to call the parent function here:
+ parent::options_validate($form, $form_state);
+
+ if ($form_state['values']['form_id'] == 'views_ui_config_item_form') {
+ $check_fields = array_filter($form_state['values']['options']['date_fields']);
+ if (empty($check_fields)) {
+ form_error($form['date_fields'], t('You must select at least one date field for this argument.'));
+ }
+ if (!preg_match('/^(?:\-[0-9]{1,4}|[0-9]{4}):(?:[\+|\-][0-9]{1,4}|[0-9]{4})$/', $form_state['values']['options']['year_range'])) {
+ form_error($form['year_range'], t('Date year range must be in the format -9:+9, 2005:2010, -9:2010, or 2005:+9'));
+ }
+ }
+ }
+
+ function options_submit($form, &$form_state) {
+ // It is very important to call the parent function here:
+ parent::options_submit($form, $form_state);
+
+ if ($form_state['values']['form_id'] == 'views_ui_config_item_form') {
+ $form_state['values']['options']['date_fields'] = array_filter($form_state['values']['options']['date_fields']);
+ }
+ }
+
+ // Update the summary values to show selected granularity.
+ function admin_summary() {
+ $fields = date_api_fields($this->definition['base']);
+ if (!empty($this->options['date_fields'])) {
+ $output = array();
+ foreach ($this->options['date_fields'] as $field) {
+ $output[] = $fields['name'][$field]['label'];
+ }
+ return implode(' '. $this->options['date_method'] .' ', $output);
+ }
+ else {
+ return parent::admin_summary();
+ }
+ }
+
+ /**
+ * Set the empty argument value to the current date,
+ * formatted appropriately for this argument.
+ */
+ function get_default_argument($raw = FALSE) {
+ $granularity = $this->options['granularity'];
+ if (!$raw && $this->options['default_argument_type'] == 'date') {
+ if ($granularity == 'week') {
+ $now = date_now();
+ $week = date_week(date_format($now, 'Y-m-d'));
+ return date_format($now, 'Y') .'-W'. $week;
+ }
+ else {
+ return date($this->format(), time());
+ }
+ }
+ else {
+ return parent::get_default_argument($raw);
+ }
+ }
+
+ function format() {
+ if (!empty($this->options['granularity'])) {
+ $date_handler = new date_sql_handler();
+ return $date_handler->views_formats($this->options['granularity']);
+ }
+ else {
+ return !empty($this->options[$this->option_name]) ? $this->options[$this->option_name] : 'Y-m';
+ }
+ }
+
+ /**
+ * Provide a link to the next level of the view from the summary.
+ */
+ function summary_name($data) {
+ $format = $this->date_handler->views_formats($this->options['granularity'], 'display');
+ $value = $data->{$this->name_alias};
+ $range = $this->date_handler->arg_range($value);
+ return date_format_date($range[0], 'custom', $format);
+ }
+
+ /**
+ * Provide the argument to use to link from the summary to the next level;
+ * this will be called once per row of a summary, and used as part of
+ * $view->get_url().
+ *
+ * @param $data
+ * The query results for the row.
+ */
+ function summary_argument($data) {
+ $format = $this->date_handler->views_formats($this->options['granularity'], 'sql');
+ $value = $data->{$this->name_alias};
+ $range = $this->date_handler->arg_range($value);
+ return date_format_date($range[0], 'custom', $format);
+ }
+
+ /**
+ * Provide a link to the next level of the view from the argument.
+ */
+ function title() {
+ $format = $this->date_handler->views_formats($this->options['granularity'], 'display');
+ $range = $this->date_handler->arg_range($this->argument);
+ return date_format_date($range[0], 'custom', $format);
+ }
+
+ /**
+ * Create a summary query that matches the granularity.
+ *
+ * Needed or Views will do a groupby on the complete date instead
+ * of only the part of the date actually used in the argument.
+ */
+ function summary_query() {
+ $this->get_query_fields();
+
+ // No way to do summaries on more than one field at a time.
+ if (count($this->query_fields) > 1) {
+ return;
+ }
+
+ // Cause query->ensure_table to perform the correct join.
+ $this->table = $this->query_fields[0]['field']['table_name'];
+ $this->ensure_my_table();
+
+ $field = $this->query_fields[0]['field'];
+ $date_handler = $this->query_fields[0]['date_handler'];
+
+ // Get the SQL format for this granularity, like Y-m,
+ // and use that as the grouping value.
+ $format = $date_handler->views_formats($this->options['granularity'], 'sql');
+ $this->formula = $date_handler->sql_format($format, $date_handler->sql_field($field['fullname']));
+
+ // Add the computed field.
+ $this->base_alias = $this->name_alias = $this->query->add_field(NULL, $this->formula, $field['query_name']);
+
+ return $this->summary_basics(FALSE);
+ }
+
+ function get_query_fields() {
+ $fields = date_api_fields($this->definition['base']);
+ $fields = $fields['name'];
+ $min_date = isset($this->min_date) ? $this->min_date : NULL;
+ $min_utc = isset($this->min_utc) ? $this->min_utc : NULL;
+ $max_date = isset($this->max_date) ? $this->max_date : NULL;
+ $max_utc = isset($this->max_utc) ? $this->max_utc : NULL;
+ $this->query_fields = array();
+ foreach ($this->options['date_fields'] as $delta => $name) {
+ if (array_key_exists($name, $fields) && $field = $fields[$name]) {
+ $date_handler = new date_sql_handler();
+ $date_handler->construct($field['sql_type'], date_default_timezone_name());
+ $date_handler->granularity = $this->options['granularity'];
+ date_views_set_timezone($date_handler, $this, $field);
+ $this->query_fields[] = array('field' => $field, 'date_handler' => $date_handler);
+ }
+ }
+ }
+
+ /**
+ * Make sure the date field is added to the query.
+ *
+ * Do this in pre_query() so it will get done even if the argument
+ * is the wildcard, since query() is skipped when the wildcard is used.
+ */
+ function pre_query() {
+ // Unset invalid date values before the query runs.
+ if (!empty($this->view->args) && count($this->view->args) > $this->position) {
+ $argument = $this->view->args[$this->position];
+ $parts = $this->date_handler->arg_parts($argument);
+ if (empty($parts[0]['date']) && empty($parts[0]['period'])) {
+ unset($this->view->args[$this->position]);
+ }
+ }
+ }
+
+ /**
+ * Set up the query for this argument.
+ *
+ * The argument sent may be found at $this->argument.
+ */
+ function query() {
+ $block_identifier = date_block_identifier($this->view);
+ if (!empty($this->view->block_identifier) || isset($_GET[$block_identifier])) {
+ // Retrieve the block arguments in a way that will work for
+ // urls like user/%/calendar/2009-04.
+ if (!empty($_GET[$block_identifier])) {
+ $path_args = explode('/', $this->view->get_path());
+ $mini_args = explode('/', $_GET[$block_identifier]);
+ foreach ($path_args as $pos => $key) {
+ if ($path_args[$pos] != '%') {
+ unset($mini_args[$pos]);
+ }
+ }
+ // Get rid of gaps in the array caused by embedded args.
+ $mini_args = array_values($mini_args);
+ $this->view->args = $mini_args;
+ }
+ $i = 0;
+ foreach ($this->view->argument as $argument) {
+ if ($argument->field == 'date_argument') {
+ $this->argument = $this->view->args[$argument->position];
+ break;
+ }
+ $i++;
+ }
+ }
+ $parts = $this->date_handler->arg_parts($this->argument);
+
+ foreach ($parts as $type) {
+ foreach ($type as $part) {
+ foreach ($part as $key => $value) {
+ if (!empty($value)) {
+ // The last part evaluated is the one that will 'stick'
+ // as the date type.
+ $this->granularity = $key;
+ $this->$key = $value;
+ }
+ }
+ }
+ }
+
+ $range = $this->date_handler->arg_range($this->argument);
+ $min_date = $range[0];
+ $max_date = $range[1];
+ $this->min_date = $min_date;
+ $this->max_date = $max_date;
+
+ // See if we're outside the allowed date range for our argument.
+ if (date_format($min_date, 'Y') < $this->view->date_info->min_allowed_year || date_format($max_date, 'Y') > $this->view->date_info->max_allowed_year) {
+ $this->forbid = TRUE;
+ $this->query->add_where('date', "0=1");
+ return;
+ }
+
+ // The second option seems to work better in the block view if
+ // set to something other than the original value.
+ // Need to keep an eye on this to be sure nothing else breaks.
+ //$format = $this->date_handler->views_formats($this->options['granularity'], 'sql');
+ $format = $this->date_handler->views_formats($this->granularity, 'sql');
+ $this->get_query_fields();
+ if (!empty($this->query_fields)) {
+ // Use set_where_group() with the selected date_method
+ // of 'AND' or 'OR' to create the where clause.
+ $this->query->set_where_group($this->options['date_method'], 'date');
+ foreach ($this->query_fields as $query_field) {
+ $field = $query_field['field'];
+ if ($field['table_name'] != $this->table || !empty($this->relationship)) {
+ $this->related_table_alias = $this->query->ensure_table($field['table_name'], $this->relationship);
+ }
+ $date_handler = $query_field['date_handler'];
+ $table_alias = !empty($this->related_table_alias) ? $this->related_table_alias : $field['table_name'];
+ $from_field = str_replace($field['table_name'] .'_', $table_alias .'.', $field['fromto'][0]);
+ $to_field = str_replace($field['table_name'] .'_', $table_alias .'.', $field['fromto'][1]);
+
+ if ($this->granularity != 'week') {
+ $from = $date_handler->sql_where_format($format, $from_field, '<=', date_format($max_date, $format));
+ $to = $date_handler->sql_where_format($format, $to_field, '>=', date_format($min_date, $format));
+ }
+ else {
+ $format = DATE_FORMAT_DATETIME;
+ $from = $date_handler->sql_where_date('DATE', $from_field, '<=', date_format($max_date, $format));
+ $to = $date_handler->sql_where_date('DATE', $to_field, '>=', date_format($min_date, $format));
+ }
+ $sql = str_replace('***table***', $field['table_name'], "($from AND $to)");
+ if ($sql) {
+ $this->query->add_where('date', $sql);
+ }
+ }
+ }
+ }
+}
diff --git a/sites/all/modules/date/includes/date_api_fields.inc b/sites/all/modules/date/includes/date_api_fields.inc
new file mode 100644
index 0000000..2e4c112
--- /dev/null
+++ b/sites/all/modules/date/includes/date_api_fields.inc
@@ -0,0 +1,179 @@
+ $val) {
+ $fromto = array();
+ $tmp = explode('.', $name);
+ $field_name = $tmp[1];
+ $table_name = $tmp[0];
+ $alias = str_replace('.', '_', $name);
+
+ if (!$handler = views_get_handler($table_name, $field_name, 'field')) {
+ continue;
+ }
+
+ $handler_name = $handler->definition['handler'];
+ $type = '';
+
+ // For cck fields, get the date type.
+ $custom = array();
+ if (isset($handler->content_field)) {
+ if ($handler->content_field['type'] == 'date') {
+ $type = 'cck_string';
+ }
+ elseif ($handler->content_field['type'] == 'datestamp') {
+ $type = 'cck_timestamp';
+ }
+ elseif ($handler->content_field['type'] == 'datetime') {
+ $type = 'cck_datetime';
+ }
+ }
+
+ // Allow custom modules to provide date fields.
+ // The is_a() function makes this work for any handler
+ // that was derived from 'views_handler_field_date'.
+ // Unfortunately is_a() is deprecated in PHP 5.2, so we need
+ // a more convoluted test.
+ elseif ((version_compare(PHP_VERSION, '5.2', '<') && is_a($handler, 'views_handler_field_date')) || ($handler instanceof views_handler_field_date)) {
+ foreach (module_implements('date_api_fields') as $module) {
+ $function = $module .'_date_api_fields';
+ if ($custom = $function("$table_name.$field_name")) {
+ $type = 'custom';
+ break;
+ }
+ }
+ }
+
+ // Don't do anything if this is not a date field we can handle.
+ if (!empty($type)) {
+
+ // Handling for simple timestamp fields
+ $fromto = array($alias, $alias);
+ $tz_handling = 'site';
+ $related_fields = array();
+ $timezone_field = '';
+ $offset_field = '';
+ $rrule_field = '';
+ $delta_field = '';
+ $granularity = array('year', 'month', 'day', 'hour', 'minute');
+
+ // Handling for content field dates
+ if (isset($handler->content_field['tz_handling'])) {
+ $tz_handling = $handler->content_field['tz_handling'];
+ $db_info = content_database_info($handler->content_field);
+ if ($tz_handling == 'date') {
+ $offset_field = $table_name .'.'. $db_info['columns']['offset']['column'];
+ }
+ $related_fields = array(
+ $table_name .'.'. $field_name
+ );
+ if (isset($db_info['columns']['value2']['column'])) {
+ $related_fields = array_merge($related_fields, array($table_name .'.'. $db_info['columns']['value2']['column']));
+ }
+ if (isset($db_info['columns']['timezone']['column'])) {
+ $related_fields = array_merge($related_fields, array($table_name .'.'. $db_info['columns']['timezone']['column']));
+ $timezone_field = $table_name .'.'. $db_info['columns']['timezone']['column'];
+ }
+ if (isset($db_info['columns']['rrule']['column'])) {
+ $related_fields = array_merge($related_fields, array($table_name .'.'. $db_info['columns']['rrule']['column']));
+ $rrule_field = $table_name .'.'. $db_info['columns']['rrule']['column'];
+ }
+ }
+ // Get the delta value into the query.
+ if (!empty($handler->content_field['multiple'])) {
+ array_push($related_fields, "$table_name.delta");
+ $delta_field = $table_name .'_delta';
+ }
+
+ // Handling for cck fromto dates
+ if (isset($handler->content_field)) {
+ switch ($handler->content_field['type']) {
+ case 'date':
+ case 'datetime':
+ case 'datestamp':
+ $db_info = content_database_info($handler->content_field);
+ $fromto = array(
+ $table_name .'_'. $db_info['columns']['value']['column'],
+ $table_name .'_'. (!empty($handler->content_field['todate']) ? $db_info['columns']['value2']['column'] : $db_info['columns']['value']['column']),
+ );
+ break;
+ }
+ $granularity = !empty($handler->content_field['granularity']) ? $handler->content_field['granularity'] : array('year', 'month', 'day', 'hour', 'minute');
+ }
+
+ // CCK fields append a column name to the field, others do not
+ // need a real field_name with no column name appended for cck date formatters
+ switch ($type) {
+ case 'cck_string':
+ $sql_type = DATE_ISO;
+ break;
+ case 'cck_datetime':
+ $sql_type = DATE_DATETIME;
+ break;
+ default:
+ $sql_type = DATE_UNIX;
+ break;
+ }
+ $fields['name'][$name] = array(
+ 'type' => $type,
+ 'sql_type' => $sql_type,
+ 'label' => $val['group'] .': '. $val['title'],
+ 'granularity' => $granularity,
+ 'fullname' => $name,
+ 'table_name' => $table_name,
+ 'field_name' => $field_name,
+ 'query_name' => $alias,
+ 'fromto' => $fromto,
+ 'tz_handling' => $tz_handling,
+ 'offset_field' => $offset_field,
+ 'timezone_field' => $timezone_field,
+ 'rrule_field' => $rrule_field,
+ 'related_fields' => $related_fields,
+ 'delta_field' => $delta_field,
+ );
+
+ // Allow the custom fields to over-write values.
+ if (!empty($custom)) {
+ foreach ($custom as $key => $val) {
+ $fields['name'][$name][$key] = $val;
+ }
+ }
+ if (isset($handler->content_field)) {
+ if (drupal_substr($field_name, -1) == '2') {
+ $len = (drupal_strlen($field_name) - 7);
+ }
+ else {
+ $len = (drupal_strlen($field_name) - 6);
+ }
+ $fields['name'][$name]['real_field_name'] = drupal_substr($field_name, 0, $len);
+ }
+ else {
+ $fields['name'][$name]['real_field_name'] = $field_name;
+ }
+ $fields['alias'][$alias] = $fields['name'][$name];
+ }
+ }
+ cache_set($cid, $fields, 'cache_views');
+ return $fields;
+}
diff --git a/sites/all/modules/date/includes/date_api_filter_handler.inc b/sites/all/modules/date/includes/date_api_filter_handler.inc
new file mode 100644
index 0000000..3c96004
--- /dev/null
+++ b/sites/all/modules/date/includes/date_api_filter_handler.inc
@@ -0,0 +1,617 @@
+date_handler = new date_sql_handler();
+ $this->date_handler->construct();
+ $this->date_handler->granularity = $this->options['granularity'];
+ }
+
+ function init(&$view, $options) {
+ parent::init($view, $options);
+ $handler = $this->date_handler;
+ $handler->granularity = isset($options['granularity']) ? $options['granularity'] : 'day';
+ $handler->adjustment_field = isset($options['adjustment_field']) ? $options['adjustment_field'] : 0;
+
+ if (empty($this->view->date_info)) $this->view->date_info = new stdClass();
+
+ // Set the view range, do this only if not already set in case there are multiple date arguments.
+ if (empty($this->view->date_info->min_allowed_year)) {
+ $range = date_range_years($this->options['year_range']);
+ $this->view->date_info->min_allowed_year = !empty($range) && is_array($range) ? $range[0] : variable_get('min_allowed_year', 100);
+ $this->view->date_info->max_allowed_year = !empty($range) && is_array($range) ? $range[1] : variable_get('max_allowed_year', 4000);
+ }
+ if (empty($this->view->date_info->date_fields)) {
+ $this->view->date_info->date_fields = array();
+ }
+ $this->view->date_info->date_fields = array_merge($this->view->date_info->date_fields, $this->options['date_fields']);
+ $this->definition['allow empty'] = TRUE;
+
+ // If no value has been submitted on an exposed filter it is treated as
+ // a submitted value. Send a flag to the date widget processors so they
+ // know to set '#value' instead of '#default_value' in that case.
+ $this->force_value = FALSE;
+ if (empty($this->options['exposed']) || (isset($this->options['expose']['identifier']) && !isset($_GET[$this->options['expose']['identifier']]))) {
+ $this->force_value = TRUE;
+ }
+
+ }
+
+ // Set default values for the date filter.
+ function option_definition() {
+ $options = parent::option_definition();
+ $options['date_fields'] = array('default' => array());
+ $options['date_method'] = array('default' => 'OR', 'export' => 'export_plugin');
+ $options['granularity'] = array('default' => 'day', 'export' => 'export_plugin');
+ $options['form_type'] = array('default' => 'date_select', 'export' => 'export_plugin');
+ $options['default_date'] = array('default' => '', 'export' => 'export_plugin');
+ $options['default_to_date'] = array('default' => '', 'export' => 'export_plugin');
+ $options['year_range'] = array('default' => '-3:+3', 'export' => 'export_plugin');
+ return $options;
+ }
+
+ function operators() {
+ $operators = parent::operators();
+ $operators['contains'] = array(
+ 'title' => t('Contains'),
+ 'short' => t('contains'),
+ 'values' => 1,
+ );
+ return $operators;
+ }
+
+ /**
+ * Make sure our custom options get exported.
+ * Handle the options we know about, pass the rest to the parent plugin.
+ */
+ function export_plugin($indent, $prefix, $storage, $option, $definition, $parents) {
+ $output = '';
+ if (in_array($option, array('date_method', 'granularity', 'form_type', 'default_date', 'default_to_date', 'year_range'))) {
+ $name = $this->options[$option];
+ $output .= $indent . $prefix . "['$option'] = '$name';\n";
+ return $output;
+ }
+ return parent::export_plugin($indent, $prefix, $storage, $option, $definition, $parents);
+ }
+
+ /**
+ * Set the granularity of the date parts to use in the filter.
+ */
+ function has_extra_options() { return TRUE; }
+
+ /**
+ * Date selection options.
+ *
+ * TODO Only select widget is working right now.
+ */
+ function widget_options() {
+ $options = array(
+ 'date_select' => t('Select'),
+ 'date_text' => t('Text'),
+ 'date_popup' => t('Popup'),
+ );
+ if (!module_exists('date_popup')) {
+ unset($options['date_popup']);
+ }
+ return $options;
+ }
+
+ function year_range() {
+ $year_range = explode(':', $this->options['year_range']);
+ if (drupal_substr($this->options['year_range'], 0, 1) == '-' || $year_range[0] < 0) {
+ $this_year = date_format(date_now(), 'Y');
+ $year_range[0] = $this_year + $year_range[0];
+ $year_range[1] = $this_year + $year_range[1];
+ }
+ return $year_range;
+ }
+
+ function extra_options_form(&$form, &$form_state) {
+ $form['form_type'] = array(
+ '#type' => 'radios',
+ '#title' => t('Date form type'),
+ '#default_value' => $this->options['form_type'],
+ '#options' => $this->widget_options(),
+ '#description' => t('Choose the form element to use for date selection.'),
+ );
+
+ $form['granularity'] = $this->date_handler->granularity_form($this->options['granularity']);
+ $form['granularity']['#description'] = '
'. t("Select a granularity for the date filter. For instance, selecting 'day' will create a filter where users can select the year, month, and day.") .'
';
+
+ $form['year_range'] = array(
+ '#title' => t('Date year range'),
+ '#type' => 'textfield',
+ '#default_value' => $this->options['year_range'],
+ '#description' => t("Set the allowable minimum and maximum year range for this argument, either a -X:+X offset from the current year, like '-3:+3' or an absolute minimum and maximum year, like '2005:2010'. When the argument is set to a date outside the range, the page will be returned as 'Page not found (404)'."),
+ );
+
+ $fields = date_api_fields($this->definition['base']);
+ $options = array();
+ foreach ($fields['name'] as $name => $field) {
+ $options[$name] = $field['label'];
+ }
+
+ // If this filter was added as a CCK field filter and no other date field
+ // has been chosen, update the default with the right date.
+ if (empty($this->options['date_fields']) && $this->field != 'date_filter') {
+ $this->options['date_fields'] = array($this->table .'.'. $this->field);
+ }
+ $form['date_fields'] = array(
+ '#title' => t('Date field(s)'),
+ '#type' => 'checkboxes',
+ '#options' => $options,
+ '#default_value' => $this->options['date_fields'],
+ '#multiple' => FALSE,
+ '#description' => t('Select date field(s) to filter with this argument.'),
+ );
+ $form['date_method'] = array(
+ '#title' => t('Method'),
+ '#type' => 'radios',
+ '#options' => array('OR' => t('OR'), 'AND' => t('AND')),
+ '#default_value' => $this->options['date_method'],
+ '#description' => t('Method of handling multiple date fields in the same query. Return items that have any matching date field (date = field_1 OR field_2), or only those with matches in all selected date fields (date = field_1 AND field_2).'),
+ );
+ }
+
+ function extra_options_validate($form, &$form_state) {
+ $check_fields = array_filter($form_state['values']['options']['date_fields']);
+ if (empty($check_fields)) {
+ form_error($form['date_fields'], t('You must select at least one date field for this filter.'));
+ }
+ if (!preg_match('/^(?:\-[0-9]{1,4}|[0-9]{4}):(?:[\+|\-][0-9]{1,4}|[0-9]{4})$/', $form_state['values']['options']['year_range'])) {
+ form_error($form['year_range'], t('Date year range must be in the format -9:+9, 2005:2010, -9:2010, or 2005:+9'));
+ }
+ }
+
+ function extra_options_submit($form, &$form_state) {
+ $form_state['values']['options']['date_fields'] = array_filter($form_state['values']['options']['date_fields']);
+ }
+
+ /**
+ * Add the selectors to the value form using the date handler.
+ */
+ function value_form(&$form, &$form_state) {
+ // We use different values than the parent form, so we must
+ // construct our own form element.
+ $form['value'] = array();
+ $form['value']['#tree'] = TRUE;
+
+ // We have to make some choices when creating this as an exposed
+ // filter form. For example, if the operator is locked and thus
+ // not rendered, we can't render dependencies; instead we only
+ // render the form items we need.
+ $which = 'all';
+ $source = '';
+ if (!empty($form['operator'])) {
+ $source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
+ }
+
+ if (!empty($form_state['exposed'])) {
+ if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator'])) {
+ // exposed and locked.
+ $which = in_array($this->operator, $this->operator_values(2)) ? 'minmax' : 'value';
+ }
+ else {
+ $source = 'edit-' . form_clean_id($this->options['expose']['operator']);
+ }
+ }
+
+ $handler = $this->date_handler;
+
+ if ($which == 'all' || $which == 'value') {
+ $form['value'] += $this->date_parts_form($form_state, 'value', $source, $which, $this->operator_values(1));
+ if ($this->force_value) {
+ $form['value']['value']['#force_value'] = TRUE;
+ }
+ }
+
+ if ($which == 'all' || $which == 'minmax') {
+ $form['value'] += $this->date_parts_form($form_state, 'min', $source, $which, $this->operator_values(2));
+ $form['value'] += $this->date_parts_form($form_state, 'max', $source, $which, $this->operator_values(2));
+ if ($this->force_value) {
+ $form['value']['min']['#force_value'] = TRUE;
+ $form['value']['max']['#force_value'] = TRUE;
+ }
+ }
+
+ // Add some text to make it clear when additional options are available.
+ $extra = '';
+ if (version_compare(PHP_VERSION, '5.2', '>=')) {
+ $extra = t(" You can use any values PHP's date_create() can understand, like between '12AM today' and '12AM tomorrow.");
+ }
+ $form['value']['value']['#prefix'] = '';
+ $form['value']['default_date'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Date default'),
+ '#default_value' => $this->options['default_date'],
+ '#prefix' => '
' . t("Relative values will be used if no date is set above. Use 'now' to default to the current date at runtime or add modifiers like 'now +1 day'. The To date default value is used when the operator is set to 'between' or 'not between'.") . $extra .'
' . t('If the filter is exposed, these values will be used to set the inital value of the exposed filter. Leave both date and default values blank to start with no value in the exposed filter.') .'
',
+ );
+ $form['value']['default_to_date'] = array(
+ '#type' => 'textfield',
+ '#title' => t('To date default'),
+ '#default_value' => $this->options['default_to_date'],
+ );
+
+ // Test if this value is in the UI or exposed, only show these elements in the UI.
+ // We'll save it as an option rather than a value to store it for use
+ // in the exposed filter.
+ if (!empty($form_state['exposed'])) {
+ $form['value']['default_date']['#type'] = 'value';
+ $form['value']['default_date']['#value'] = $form['value']['default_date']['#default_value'];
+ $form['value']['default_to_date']['#type'] = 'value';
+ $form['value']['default_to_date']['#value'] = $form['value']['default_to_date']['#default_value'];
+ unset($form['value']['default_date']['#prefix']);
+ unset($form['value']['value']['#prefix']);
+ }
+
+ $form['value']['#theme'] = 'date_views_filter_form';
+ }
+
+ /**
+ * A form element to select date part values.
+ *
+ * @param string $prefix
+ * A prefix for the date values, 'value', 'min', or 'max'.
+ * @param string $source
+ * The operator for this element.
+ * @param string $which
+ * Which element to provide, 'all', 'value', or 'minmax'.
+ * @param array $operator_values
+ * An array of the allowed operators for this element.
+ * @param array $limit
+ * An array of date parts to limit this element to.
+ *
+ * @return
+ * The form date part element for this instance.
+ */
+ function date_parts_form($form_state, $prefix, $source, $which, $operator_values) {
+ require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_elements.inc');
+ switch ($prefix) {
+ case 'min':
+ $name = t('From date');
+ break;
+ case 'max':
+ $name = t('To date');
+ break;
+ default:
+ $name = '';
+ break;
+ }
+
+ $type = $this->options['form_type'];
+ if ($type == 'date_popup' && !module_exists('date_popup')) {
+ $type = 'date_text';
+ }
+ $format = $this->date_handler->views_formats($this->options['granularity'], 'sql');
+ $granularity = array_keys($this->date_handler->date_parts($this->options['granularity']));
+
+ // Don't set a default date in the UI, only in the exposed form.
+ $default_date = '';
+ if (!empty($form_state['exposed'])) {
+ $default_date = $this->default_value($prefix);
+ }
+
+ $form[$prefix] = array(
+ '#type' => $type,
+ '#title' => check_plain($name),
+ '#size' => 20,
+ '#default_value' => empty($this->force_value) && !empty($this->value[$prefix]) ? $this->value[$prefix] : $default_date,
+ '#date_format' => date_limit_format($format, $granularity),
+ '#date_label_position' => 'within',
+ '#date_year_range' => $this->options['year_range'],
+ );
+ if ($which == 'all') {
+ $dependency = array(
+ '#process' => array($type .'_process', 'views_process_dependency'),
+ '#dependency' => array($source => $operator_values),
+ );
+ $form[$prefix] += $dependency;
+ }
+
+ return $form;
+ }
+
+ function default_value($prefix, $options = NULL) {
+ $default_date = '';
+ if (empty($options)) {
+ $options = $this->options;
+ }
+
+ // If this is a remembered value, use the value from the SESSION.
+ if (!empty($this->options['expose']['remember'])) {
+ $display_id = ($this->view->display_handler->is_defaulted('filters')) ? 'default' : $this->view->current_display;
+ $value = $_SESSION['views'][$this->view->name][$display_id]['date_filter'][$prefix];
+ if (!empty($value)) {
+ return $value;
+ }
+ }
+
+ // This is a date that needs to be constructed from options like 'now'.
+ $default_option = $prefix == 'max' ? $options['default_to_date'] : $options['default_date'];
+ if (!empty($default_option)) {
+ // For PHP 5.2+, take advantage of any strings that native PHP
+ // date_create() can handle. For older versions use strtotime().
+ if (version_compare(PHP_VERSION, '5.2', '<')) {
+ $now = strtotime($default_option .' UTC');
+ $date = date_create("@$now", timezone_open('UTC'));
+ }
+ else {
+ $date = date_create($default_option, date_default_timezone());
+ }
+ $default_date = date_format($date, DATE_FORMAT_DATETIME);
+ }
+ // This a fixed date.
+ else {
+ $default_date = $options['value'][$prefix];
+ }
+ return $default_date;
+ }
+
+ /**
+ * Value validation.
+ *
+ * TODO add in more validation.
+ *
+ * We are setting an extra option using a value form
+ * because it makes more sense to set it there.
+ * That's not the normal method, so we have to manually
+ * transfer the selected value back to the option.
+ */
+ function value_validate($form, &$form_state) {
+ if (($form_state['values']['options']['operator'] == 'between' || $form_state['values']['options']['operator'] == 'not between') &&
+ !empty($form_state['values']['options']['value']['default_date']) && empty($form_state['values']['options']['value']['default_to_date'])) {
+ form_error($form['value']['default_to_date'], t('Please set a default value for the To date as well as the From date when using default values with the Between or Not between operators.'));
+ }
+ if (isset($form_state['values']['options']['value']['default_date'])) {
+ $this->options['default_date'] = $form_state['values']['options']['value']['default_date'];
+ $this->options['default_to_date'] = $form_state['values']['options']['value']['default_to_date'];
+ }
+ parent::value_validate($form, $form_state);
+ }
+
+ // Update the summary values to provide
+ // meaningful information for each option.
+ function admin_summary() {
+ if (empty($this->options['date_fields'])) {
+ return t('Missing date fields!');
+ }
+ $handler = $this->date_handler;
+
+ $fields = date_api_fields($this->definition['base']);
+ if (!empty($this->options['date_fields'])) {
+ $output = array();
+ foreach ($this->options['date_fields'] as $field) {
+ if (array_key_exists($field, $fields['name'])) {
+ $output[] = $fields['name'][$field]['label'];
+ }
+ }
+ }
+ $field = implode(' '. $this->options['date_method'] .' ', $output);
+ $output = "$field ". check_plain($this->operator) . ' ';
+ $parts = $handler->date_parts();
+ $widget_options = $this->widget_options();
+ // If the filter is exposed, display the granularity.
+ if ($this->options['exposed']) {
+ return t('(@field) Exposed @widget @format', array('@field' => $field, '@format' => $parts[$handler->granularity], '@widget' => $widget_options[$this->options['form_type']]));
+ }
+ // If not exposed, display the value.
+ if (in_array($this->operator, $this->operator_values(2))) {
+ $min = check_plain(!empty($this->options['default_date']) ? $this->options['default_date'] : $this->options['value']['min']);
+ $max = check_plain(!empty($this->options['default_to_date']) ? $this->options['default_to_date'] : $this->options['value']['max']);
+ $output .= t('@min and @max', array('@min' => $min, '@max' => $max));
+ }
+ else {
+ $output .= check_plain(!empty($this->options['default_date']) ? $this->options['default_date'] : $this->options['value']['value']);
+ }
+ return $output;
+ }
+
+ // Views treats the form as though it has already been submitted
+ // even when it hasn't, so we when it is really not submitted we
+ // have to adjust the values to match what should have been the default.
+ // Overriding exposed_submit() will ensure that the $input value
+ // used by Views has been adjusted to the right value.
+ function exposed_submit(&$form, &$form_state) {
+ if ($this->force_value) {
+ $default = array();
+ foreach (array('value', 'min', 'max') as $prefix) {
+ $default[$prefix] = $this->default_value($prefix);
+ }
+ $form_state['values'][$this->options['expose']['identifier']] = $default;
+ }
+ }
+
+ /**
+ * Custom implementation of query() so we can get the
+ * AND and OR methods in the right places.
+ */
+ function query() {
+ $this->get_query_fields();
+ if (!empty($this->query_fields)) {
+ foreach ((array) $this->query_fields as $query_field) {
+ $field = $query_field['field'];
+ if (!isset($this->query->table_queue[$field['table_name']])) {
+ if ($field['table_name'] != $this->table || !empty($this->relationship)) {
+ $this->related_table_alias = $this->query->ensure_table($field['table_name'], $this->relationship);
+ }
+ }
+ $table_alias = !empty($this->related_table_alias) ? $this->related_table_alias : $field['table_name'];
+ $query_field['field']['fullname'] = $table_alias .'.'. $query_field['field']['field_name'];
+
+ $sql = '';
+ $sql_parts = array();
+
+ switch ($this->operator) {
+ case 'between':
+ $sql_parts[] = $this->date_filter('min', $query_field, '>=');
+ $sql_parts[] = $this->date_filter('max', $query_field, '<=');
+ $sql = implode(' AND ', array_filter($sql_parts));
+ break;
+
+ case 'not between':
+ $sql_parts[] = $this->date_filter('min', $query_field, '<');
+ $sql_parts[] = $this->date_filter('max', $query_field, '>');
+ $sql = implode(' OR ', array_filter($sql_parts));
+ break;
+
+ case 'contains':
+ $query_field['field']['fullname'] = str_replace($field['table_name'] .'_', $table_alias .'.', $field['fromto'][0]);
+ $sql_parts[] = $this->date_filter('value', $query_field, '<=');
+ $query_field['field']['fullname'] = str_replace($field['table_name'] .'_', $table_alias .'.', $field['fromto'][1]);
+ $sql_parts[] = $this->date_filter('value', $query_field, '>=');
+ $sql = implode(' AND ', array_filter($sql_parts));
+ break;
+
+ default:
+ $sql = $this->date_filter('value', $query_field, $this->operator);
+ break;
+ }
+
+ if (!empty($sql)) {
+ // Use set_where_group() with the selected date_method
+ // of 'AND' or 'OR' to combine the field WHERE clauses.
+ $this->query->set_where_group($this->options['date_method'], 'date');
+ $this->query->add_where('date', $sql);
+ }
+ }
+ }
+ }
+
+ function date_filter($prefix, $query_field, $operator) {
+ $field = $query_field['field'];
+
+ // Handle the simple operators first.
+ if ($operator == 'empty') {
+ $this->add_date_field($field);
+ return $field['fullname'] .' IS NULL';
+ }
+ elseif ($operator == 'not empty') {
+ $this->add_date_field($field);
+ return $field['fullname'] .' IS NOT NULL';
+ }
+
+ // Views treats the default values as though they are submitted
+ // so we when it is really not submitted we have to adjust the
+ // query to match what should have been the default.
+ $value_parts = !is_array($this->value[$prefix]) ? array($this->value[$prefix]) : $this->value[$prefix];
+ foreach ($value_parts as $part) {
+ $default = $this->default_value($prefix);
+ if (!empty($this->force_value) && !empty($default)) {
+ $this->value[$prefix] = $default;
+ }
+ else {
+ if (empty($part)) {
+ return '';
+ }
+ }
+ }
+
+ $this->add_date_field($field);
+ $granularity = $this->options['granularity'];
+ $date_handler = $query_field['date_handler'];
+ $this->format = $date_handler->views_formats($granularity, 'sql');
+ $complete_date = date_fuzzy_datetime($this->value[$prefix]);
+ $date = date_make_date($complete_date);
+ $value = date_format($date, $this->format);
+
+ $range = $this->date_handler->arg_range($value);
+ $year_range = date_range_years($this->options['year_range']);
+ if ($this->operator != 'not between') {
+ switch ($operator) {
+ case '>':
+ case '>=':
+ $range[1] = date_make_date(date_pad($year_range[1], 4) .'-12-31 23:59:59');
+ if ($operator == '>') {
+ date_modify($range[0], '+1 second');
+ }
+ break;
+ case '<':
+ case '<=':
+ $range[0] = date_make_date(date_pad($year_range[0], 4) .'-01-01 00:00:00');
+ if ($operator == '<') {
+ date_modify($range[1], '-1 second');
+ }
+ break;
+ }
+ }
+
+ $min_date = $range[0];
+ $max_date = $range[1];
+
+ $this->min_date = $min_date;
+ $this->max_date = $max_date;
+ $this->year = date_format($date, 'Y');
+ $this->month = date_format($date, 'n');
+ $this->day = date_format($date, 'j');
+ $this->week = date_week(date_format($date, DATE_FORMAT_DATE));
+ $this->date_handler = $date_handler;
+
+ if ($this->date_handler->granularity == 'week') {
+ $this->format = DATE_FORMAT_DATETIME;
+ }
+ switch ($prefix) {
+ case 'min':
+ $value = date_format($min_date, $this->format);
+ break;
+ case 'max':
+ $value = date_format($max_date, $this->format);
+ break;
+ default:
+ $value = date_format($date, $this->format);
+ break;
+ }
+
+ if ($this->date_handler->granularity != 'week') {
+ $sql = $date_handler->sql_where_format($this->format, $field['fullname'], $operator, $value);
+ }
+ else {
+ $sql = $date_handler->sql_where_date('DATE', $field['fullname'], $operator, $value);
+ }
+ return $sql;
+ }
+
+ function add_date_field($field) {
+ // Explicitly add this table using add_table so Views does not
+ // remove it if it is a duplicate, since that will break the query.
+ $this->query->add_table($field['table_name'], NULL, NULL, $field['table_name']);
+ return;
+ }
+
+ function get_query_fields() {
+ $fields = date_api_fields($this->definition['base']);
+ $fields = $fields['name'];
+ $this->query_fields = array();
+ foreach ((array) $this->options['date_fields'] as $delta => $name) {
+ if (array_key_exists($name, $fields) && $field = $fields[$name]) {
+ $date_handler = new date_sql_handler();
+ $date_handler->construct($field['sql_type'], date_default_timezone_name());
+ $date_handler->granularity = $this->options['granularity'];
+ date_views_set_timezone($date_handler, $this->view, $field);
+ $this->query_fields[] = array('field' => $field, 'date_handler' => $date_handler);
+ }
+ }
+ }
+}
+
diff --git a/sites/all/modules/date/includes/date_navigation_plugin_style.inc b/sites/all/modules/date/includes/date_navigation_plugin_style.inc
new file mode 100644
index 0000000..bed360d
--- /dev/null
+++ b/sites/all/modules/date/includes/date_navigation_plugin_style.inc
@@ -0,0 +1,68 @@
+display->handler->get_option('arguments');
+ $count = 0;
+ $found = FALSE;
+ foreach ($arguments as $id => $argument) {
+ if ($argument['field'] == 'date_argument') {
+ if ($count > 0) {
+ $errors[] = t('The %style cannot use more than one Date: Date argument.', array('%style' => $this->definition['title']));
+ }
+ elseif ($argument['default_argument_type'] != 'date') {
+ $errors[] = t('The %style requires the Date: Date argument be set to default to the current date.', array('%style' => $this->definition['title']));
+ }
+ $count++;
+ $found = TRUE;
+ }
+ }
+ if (!$found) {
+ $errors[] = t('The %style requires the Date: Date argument.', array('%style' => $this->definition['title']));
+ }
+ return $errors;
+ }
+
+ function query() {
+ require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_sql.inc');
+
+ // Bring the argument information into the view so our theme can access it.
+ $i = 0;
+ foreach ($this->view->argument as $id => $argument) {
+ if ($id == 'date_argument') {
+ $this->view->date_info->granularity = $argument->granularity;
+ $this->view->date_info->date_arg = !empty($this->view->args) && count($this->view->args) > $argument->position ? $this->view->args[$argument->position] : '';
+ $this->view->date_info->date_arg_pos = $i;
+ $this->view->date_info->year = isset($argument->year) ? $argument->year : NULL;
+ $this->view->date_info->month = isset($argument->month) ? $argument->month: NULL;
+ $this->view->date_info->day = isset($argument->day) ? $argument->day : NULL;
+ $this->view->date_info->week = isset($argument->week) ? $argument->week : NULL;
+ $this->view->date_info->min_date = $argument->min_date;
+ $this->view->date_info->max_date = $argument->max_date;
+ $this->view->date_info->url = $this->view->get_url();
+ }
+ $i++;
+ }
+
+ // bring the node type into the query so we can use it in the theme
+ $this->view->query->add_field('node', 'type');
+
+ }
+}
diff --git a/sites/all/modules/date/includes/date_plugin_display_attachment.inc b/sites/all/modules/date/includes/date_plugin_display_attachment.inc
new file mode 100644
index 0000000..2074f80
--- /dev/null
+++ b/sites/all/modules/date/includes/date_plugin_display_attachment.inc
@@ -0,0 +1,39 @@
+ 'CCK UI',
+ 'description' => 'Test creation of various date fields and widgets using CCK UI.',
+ 'group' => 'Date',
+ );
+ }
+
+ function setUp() {
+ // Load the date_api module.
+ parent::setUp('content', 'date_api', 'date_timezone', 'date', 'date_popup', 'jquery_ui');
+
+ // Create and log in our privileged user.
+ $this->privileged_user = $this->drupalCreateUser(array(
+ 'administer content types', 'administer nodes'
+ ));
+ $this->drupalLogin($this->privileged_user);
+
+ variable_set('date_format_long', 'D, m/d/Y - H:i');
+ variable_set('date_format_short', 'm/d/Y - H:i');
+ variable_set('date_popup_timepicker', 'none');
+ }
+
+ function testDate() {
+ // Creates select list date field stored as a date with default settings.
+ $this->createDateField($type = 'date', $widget = 'date_select');
+ $edit = array();
+ $this->drupalPost(NULL, $edit, t('Save field settings'));
+ $this->dateForm($options = 'select');
+ $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a date field using the date_select widget.');
+ $this->deleteDateField();
+ // Creates text date field stored as a date with default settings.
+ $this->createDateField($type = 'date', $widget = 'date_text');
+ $edit = array();
+ $this->drupalPost(NULL, $edit, t('Save field settings'));
+ $this->dateForm($options = 'text');
+ $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a date field using the date_text widget.');
+ $this->deleteDateField();
+ // Creates popup date field stored as a date with default settings.
+ $this->createDateField($type = 'date', $widget = 'date_popup');
+ $edit = array(
+ 'input_format' => 'm/d/Y - H:i',
+ );
+ $this->drupalPost(NULL, $edit, t('Save field settings'));
+ $this->dateForm($options = 'popup');
+ $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a date field using the date_popup widget.');
+ $this->deleteDateField();
+ // Creates select list date field stored as a datestamp with default settings.
+ $this->createDateField($type = 'datestamp', $widget = 'date_select');
+ $edit = array();
+ $this->drupalPost(NULL, $edit, t('Save field settings'));
+ $this->dateForm($options = 'select');
+ $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a datestamp field using the date_select widget.');
+ $this->deleteDateField();
+ // Creates text date field stored as a datestamp with default settings.
+ $this->createDateField($type = 'datestamp', $widget = 'date_text');
+ $edit = array();
+ $this->drupalPost(NULL, $edit, t('Save field settings'));
+ $this->dateForm($options = 'text');
+ $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a datestamp field using the date_text widget.');
+ $this->deleteDateField();
+ // Creates popup date field stored as a datestamp with default settings.
+ $this->createDateField($type = 'datestamp', $widget = 'date_popup');
+ $edit = array(
+ 'input_format' => 'm/d/Y - H:i',
+ );
+ $this->drupalPost(NULL, $edit, t('Save field settings'));
+ $this->dateForm($options = 'popup');
+ $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a datestamp field using the date_popup widget.');
+ $this->deleteDateField();
+ // Creates select list date field stored as a datetime with default settings.
+ $this->createDateField($type = 'datetime', $widget = 'date_select');
+ $edit = array();
+ $this->drupalPost(NULL, $edit, t('Save field settings'));
+ $this->dateForm($options = 'select');
+ $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a datetime field using the date_select widget.');
+ $this->deleteDateField();
+ // Creates text date field stored as a datetime with default settings.
+ $this->createDateField($type = 'datetime', $widget = 'date_text');
+ $edit = array();
+ $this->drupalPost(NULL, $edit, t('Save field settings'));
+ $this->dateForm($options = 'text');
+ $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a datetime field using the date_text widget.');
+ $this->deleteDateField();
+ // Creates popup date field stored as a datetime with default settings.
+ $this->createDateField($type = 'datetime', $widget = 'date_popup');
+ $edit = array(
+ 'input_format' => 'm/d/Y - H:i',
+ );
+ $this->drupalPost(NULL, $edit, t('Save field settings'));
+ $this->dateForm($options = 'popup');
+ $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a datetime field using the date_popup widget.');
+ $this->deleteDateField();
+ }
+
+ function createDateField($type, $widget) {
+ $edit = array();
+ $edit['_add_new_field[label]'] = 'Test';
+ $edit['_add_new_field[field_name]'] = 'test';
+ $edit['_add_new_field[weight]'] = '-4';
+ $edit['_add_new_field[type]'] = $type;
+ $edit['_add_new_field[widget_type]'] = $widget;
+ $this->drupalPost('admin/content/node-type/story/fields', $edit, t('Save'));
+
+ }
+
+ function dateForm($options) {
+ // Tests that date field functions properly.
+ $edit = array();
+ $edit['title'] = $this->randomName(8);
+ $edit['body'] = $this->randomName(16);
+ if ($options == 'select') {
+ $edit['field_test[0][value][year]'] = '2010';
+ $edit['field_test[0][value][month]'] = '10';
+ $edit['field_test[0][value][day]'] = '7';
+ $edit['field_test[0][value][hour]'] = '10';
+ $edit['field_test[0][value][minute]'] = '30';
+ }
+ elseif ($options == 'text') {
+ $edit['field_test[0][value][date]'] = '10/07/2010 - 10:30';
+ }
+ elseif ($options == 'popup') {
+ // The default format for a popup is an odd one.
+ $edit['field_test[0][value][date]'] = '10/07/2010';
+ $edit['field_test[0][value][time]'] = '10:30';
+ }
+ $this->drupalPost('node/add/story', $edit, t('Save'));
+ $this->assertText($edit['title'], 'Test node has been created');
+ }
+
+ function deleteDateField() {
+ $this->drupalGet('admin/content/node-type/story/fields');
+ $this->clickLink('Remove');
+ $this->drupalPost(NULL, NULL, t('Remove'));
+ $this->assertText('Removed field Test from Story.', 'Removed date field.');
+ }
+}
diff --git a/sites/all/modules/date/tests/date_api.test b/sites/all/modules/date/tests/date_api.test
new file mode 100644
index 0000000..d415f41
--- /dev/null
+++ b/sites/all/modules/date/tests/date_api.test
@@ -0,0 +1,414 @@
+ t('Date API'),
+ 'description' => t('Test Date API functions.') ,
+ 'group' => t('Date'),
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ public function setUp() {
+ // Load the date_api module.
+ parent::setUp('date_api', 'date_timezone');
+ variable_set('date_api_use_iso8601', FALSE);
+ variable_set('date_first_day', 1);
+ }
+
+ function testDateAPI() {
+
+ $value = '2007-12-05 23:59';
+ $this->assertEqual(TRUE, date_part_extract($value, 'year'), "Test date_part_extract(". $value .", year), results ". date_part_extract($value, 'year'));
+ $this->assertEqual(TRUE, date_part_extract($value, 'month'), "Test date_part_extract(". $value .", mon), results ". date_part_extract($value, 'month'));
+ $this->assertEqual(TRUE, date_part_extract($value, 'day'), "Test date_part_extract(". $value .", mday), results ". date_part_extract($value, 'day'));
+
+ $this->assertEqual(TRUE, date_is_valid($value), "Test date_is_valid(". $value .")");
+ $value = '2007-00-00 00:00';
+ $this->assertNotEqual(TRUE, date_is_valid($value), "Test for invalid date_is_valid(". $value .")");
+ $value = '0000-00-00 00:00';
+ $this->assertNotEqual(TRUE, date_is_valid($value), "Test for invalid date_is_valid(". $value .")");
+ $value = '-100';
+ $this->assertNotEqual(TRUE, date_is_valid($value), "Test for invalid date_is_valid(". $value .")");
+ $value = '2007-00-01T00:00';
+ $this->assertEqual(TRUE, date_is_valid($value, DATE_ISO), "Test ISO exception to date_is_valid(". $value .", DATE_ISO)");
+
+ $dates = array(
+ '2007-01-01 00:00:00',
+ '1970-01-01 00:00:00',
+ '1900-01-01 00:00:00',
+ '1600-01-01 00:00:00',
+ '0100-01-01 00:00:00');
+ foreach ($dates as $date) {
+ $unix = date_convert($date, DATE_DATETIME, DATE_UNIX);
+ $datetime = date_convert($unix, DATE_UNIX, DATE_DATETIME);
+ $this->assertEqual($date, $datetime, 'Test roundtrip using date_convert() from DATE_DATETIME to DATE_UNIX back to DATE_DATETIME, results '. $date .' >> '. $unix .' >> '. $datetime);
+ }
+
+ // Test date_format_date().
+ $formatters = array(
+ 'a',
+ 'A',
+ 'B',
+ 'c',
+ 'd',
+ 'D',
+ 'e',
+ 'F',
+ 'g',
+ 'G',
+ 'h',
+ 'H',
+ 'i',
+ 'I',
+ 'j',
+ 'l',
+ 'L',
+ 'm',
+ 'M',
+ 'n',
+ 'N',
+ 'o',
+ 'O',
+ 'P',
+ 'r',
+ 'R',
+ 's',
+ 'S',
+ 't',
+ 'T',
+ 'u',
+ 'U',
+ 'w',
+ 'W',
+ 'y',
+ 'Y',
+ 'z',
+ 'Z',
+ );
+ foreach ($formatters as $formatter) {
+ $date_api_format = date_format_date(date_now(), 'custom', $formatter);
+ $php_format = date_format(date_now(), $formatter);
+ $this->assertEqual($date_api_format, $php_format, 'Test that the "' . $formatter . '" formatter is formatted correctly by date_format_date()');
+ }
+
+ // Test the order of the weeks days for a calendar that starts on Monday and one that starts on Sunday.
+ variable_set('date_first_day', 1);
+ $expected = array( 0 => t('Mon'), 1 => t('Tue'), 2 => t('Wed'), 3 => t('Thu'), 4 => t('Fri'), 5 => t('Sat'), 6 => t('Sun'), );
+ $days = date_week_days_ordered(date_week_days_abbr(1));
+ $this->assertEqual($expected, $days, 'Test that date_week_days_ordered() array starts on Monday when the site first day is on Monday.');
+ variable_set('date_first_day', 0);
+ $expected = array( 0 => t('Sun'), 1 => t('Mon'), 2 => t('Tue'), 3 => t('Wed'), 4 => t('Thu'), 5 => t('Fri'), 6 => t('Sat'), );
+ $days = date_week_days_ordered(date_week_days_abbr(1));
+ $this->assertEqual($expected, $days, 'Test that date_week_days_ordered() array starts on Sunday when the site first day is on Sunday.');
+
+ // Test days in February for a leap year and a non-leap year.
+ $expected = 28;
+ $value = date_days_in_month(2005, 2);
+ $this->assertEqual($expected, $value, "Test date_days_in_month(2, 2005): should be $expected, found $value.");
+ $expected = 29;
+ $value = date_days_in_month(2004, 2);
+ $this->assertEqual($expected, $value, "Test date_days_in_month(2, 2004): should be $expected, found $value.");
+
+ // Test days in year for a leap year and a non-leap year.
+ $expected = 365;
+ $value = date_days_in_year('2005-06-01 00:00:00', DATE_DATETIME);
+ $this->assertEqual($expected, $value, "Test date_days_in_year(2005-06-01, DATE_DATETIME): should be $expected, found $value.");
+ $expected = 366;
+ $value = date_days_in_year('2004-06-01 00:00:00', DATE_DATETIME);
+ $this->assertEqual($expected, $value, "Test date_days_in_year(2004-06-01, DATE_DATETIME): should be $expected, found $value.");
+
+ // Test ISO weeks for a leap year and a non-leap year.
+ $expected = 52;
+ $value = date_iso_weeks_in_year('2008-06-01 00:00:00', DATE_DATETIME);
+ $this->assertEqual($expected, $value, "Test date_iso_weeks_in_year(2008-06-01, DATE_DATETIME): should be $expected, found $value.");
+ $expected = 53;
+ $value = date_iso_weeks_in_year('2009-06-01 00:00:00', DATE_DATETIME);
+ $this->assertEqual($expected, $value, "Test date_iso_weeks_in_year(2009-06-01, DATE_DATETIME): should be $expected, found $value.");
+
+ // Test day of week for March 1, the day after leap day.
+ $expected = 6;
+ $value = date_day_of_week('2008-03-01 00:00:00', DATE_DATETIME);
+ $this->assertEqual($expected, $value, "Test date_day_of_week(2008-03-01, DATE_DATETIME): should be $expected, found $value.");
+ $expected = 0;
+ $value = date_day_of_week('2009-03-01 00:00:00', DATE_DATETIME);
+ $this->assertEqual($expected, $value, "Test date_day_of_week(2009-03-01, DATE_DATETIME): should be $expected, found $value.");
+
+ // Test day of week name for March 1, the day after leap day.
+ $expected = 'Sat';
+ $value = date_day_of_week_name('2008-03-01 00:00:00', DATE_DATETIME);
+ $this->assertEqual($expected, $value, "Test date_day_of_week_name(2008-03-01, DATE_DATETIME): should be $expected, found $value.");
+ $expected = 'Sun';
+ $value = date_day_of_week_name('2009-03-01 00:00:00', DATE_DATETIME);
+ $this->assertEqual($expected, $value, "Test date_day_of_week_name(2009-03-01, DATE_DATETIME): should be $expected, found $value.");
+
+ // Test week range with calendar weeks.
+ variable_set('date_first_day', 0);
+ variable_set('date_api_use_iso8601', FALSE);
+ $expected = '2008-01-27 to 2008-02-03';
+ $result = date_week_range(5, 2008);
+ $value = $result[0]->format(DATE_FORMAT_DATE) .' to '. $result[1]->format(DATE_FORMAT_DATE);
+ $this->assertEqual($expected, $value, "Test calendar date_week_range(5, 2008): should be $expected, found $value.");
+ $expected = '2009-01-25 to 2009-02-01';
+ $result = date_week_range(5, 2009);
+ $value = $result[0]->format(DATE_FORMAT_DATE) .' to '. $result[1]->format(DATE_FORMAT_DATE);
+ $this->assertEqual($expected, $value, "Test calendar date_week_range(5, 2009): should be $expected, found $value.");
+
+ // And now with ISO weeks.
+ variable_set('date_first_day', 1);
+ variable_set('date_api_use_iso8601', TRUE);
+ $expected = '2008-01-28 to 2008-02-04';
+ $result = date_week_range(5, 2008);
+ $value = $result[0]->format(DATE_FORMAT_DATE) .' to '. $result[1]->format(DATE_FORMAT_DATE);
+ $this->assertEqual($expected, $value, "Test ISO date_week_range(5, 2008): should be $expected, found $value.");
+ $expected = '2009-01-26 to 2009-02-02';
+ $result = date_week_range(5, 2009);
+ $value = $result[0]->format(DATE_FORMAT_DATE) .' to '. $result[1]->format(DATE_FORMAT_DATE);
+ $this->assertEqual($expected, $value, "Test ISO date_week_range(5, 2009): should be $expected, found $value.");
+ variable_set('date_api_use_iso8601', FALSE);
+
+ // Find calendar week for a date.
+ variable_set('date_first_day', 0);
+ $expected = '09';
+ $value = date_week('2008-03-01');
+ $this->assertEqual($expected, $value, "Test date_week(2008-03-01): should be $expected, found $value.");
+ $expected = '10';
+ $value = date_week('2009-03-01');
+ $this->assertEqual($expected, $value, "Test date_week(2009-03-01): should be $expected, found $value.");
+
+ // Create date object from datetime string.
+ $input = '2009-03-07 10:30';
+ $timezone = 'America/Chicago';
+ $date = date_make_date($input, $timezone);
+ $value = date_format($date, 'c');
+ $expected = '2009-03-07T10:30:00-06:00';
+ $this->assertEqual($expected, $value, "Test date_make_date($input, $timezone): should be $expected, found $value.");
+
+ // Same during daylight savings time.
+ $input = '2009-06-07 10:30';
+ $timezone = 'America/Chicago';
+ $date = date_make_date($input, $timezone);
+ $value = date_format($date, 'c');
+ $expected = '2009-06-07T10:30:00-05:00';
+ $this->assertEqual($expected, $value, "Test date_make_date($input, $timezone): should be $expected, found $value.");
+
+ // Create date object from date string.
+ $input = '2009-03-07';
+ $timezone = 'America/Chicago';
+ $date = date_make_date($input, $timezone);
+ $value = date_format($date, 'c');
+ $expected = '2009-03-07T00:00:00-06:00';
+ $this->assertEqual($expected, $value, "Test date_make_date($input, $timezone): should be $expected, found $value.");
+
+ // Same during daylight savings time.
+ $input = '2009-06-07';
+ $timezone = 'America/Chicago';
+ $date = date_make_date($input, $timezone);
+ $value = date_format($date, 'c');
+ $expected = '2009-06-07T00:00:00-05:00';
+ $this->assertEqual($expected, $value, "Test date_make_date($input, $timezone): should be $expected, found $value.");
+
+ // Create date object from date array, date only.
+ $input = array('year' => 2010, 'month' => 2, 'day' => 28);
+ $timezone = 'America/Chicago';
+ $granularity = array('year', 'month', 'day');
+ $date = date_make_date($input, $timezone, DATE_ARRAY, $granularity);
+ $value = date_format($date, 'c');
+ $expected = '2010-02-28T00:00:00-06:00';
+ $this->assertEqual($expected, $value, "Test date_make_date(array('year' => 2010, 'month' => 2, 'day' => 28), $timezone, DATE_ARRAY, array('year', 'month', 'day')): should be $expected, found $value.");
+
+ // Create date object from date array with hour.
+ $input = array('year' => 2010, 'month' => 2, 'day' => 28, 'hour' => 10);
+ $timezone = 'America/Chicago';
+ $granularity = array('year', 'month', 'day', 'hour');
+ $date = date_make_date($input, $timezone, DATE_ARRAY, $granularity);
+ $value = date_format($date, 'c');
+ $expected = '2010-02-28T10:00:00-06:00';
+ $this->assertEqual($expected, $value, "Test date_make_date(array('year' => 2010, 'month' => 2, 'day' => 28, 'hour' => 10), $timezone, DATE_ARRAY, array('year', 'month', 'day', 'hour')): should be $expected, found $value.");
+
+ // 0 = January 1, 1970 00:00:00 (UTC);
+ // 1000000000 = September 9, 2001 01:46:40 (UTC);
+
+ // Create date object from unix timestamp and convert it to a local date.
+ $input = 0;
+ $timezone = 'UTC';
+ $date = date_make_date($input, $timezone, DATE_UNIX);
+ $value = date_format($date, 'c');
+ $expected = '1970-01-01T00:00:00+00:00';
+ $this->assertEqual($expected, $value, "Test date_make_date($input, $timezone, DATE_UNIX): should be $expected, found $value.");
+
+ $expected = 'UTC';
+ $value = timezone_name_get(date_timezone_get($date));
+ $this->assertEqual($expected, $value, "The current timezone is $value: should be $expected.");
+ $expected = 0;
+ $value = date_offset_get($date);
+ $this->assertEqual($expected, $value, "The current offset is $value: should be $expected.");
+
+ $timezone = 'America/Los_Angeles';
+ date_timezone_set($date, timezone_open($timezone));
+ $value = date_format($date, 'c');
+ $expected = '1969-12-31T16:00:00-08:00';
+ $this->assertEqual($expected, $value, "Test date_timezone_set(\$date, timezone_open($timezone)): should be $expected, found $value.");
+
+ $expected = 'America/Los_Angeles';
+ $value = timezone_name_get(date_timezone_get($date));
+ $this->assertEqual($expected, $value, "The current timezone should be $expected, found $value.");
+ $expected = '-28800';
+ $value = date_offset_get($date);
+ $this->assertEqual($expected, $value, "The current offset should be $expected, found $value.");
+
+ // Convert the local version of a timestamp to UTC.
+ $input = 0;
+ $timezone = 'America/Los_Angeles';
+ $date = date_make_date($input, $timezone, DATE_UNIX);
+ $offset = date_offset_get($date);
+ $value = date_format($date, 'c');
+ $expected = '1969-12-31T16:00:00-08:00';
+ $this->assertEqual($expected, $value, "Test date_make_date($input, $timezone, DATE_UNIX): should be $expected, found $value.");
+
+ $expected = 'America/Los_Angeles';
+ $value = timezone_name_get(date_timezone_get($date));
+ $this->assertEqual($expected, $value, "The current timezone should be $expected, found $value.");
+ $expected = '-28800';
+ $value = date_offset_get($date);
+ $this->assertEqual($expected, $value, "The current offset should be $expected, found $value.");
+
+ $timezone = 'UTC';
+ date_timezone_set($date, timezone_open($timezone));
+ $value = date_format($date, 'c');
+ $expected = '1970-01-01T00:00:00+00:00';
+ $this->assertEqual($expected, $value, "Test date_timezone_set(\$date, timezone_open($timezone)): should be $expected, found $value.");
+
+ $expected = 'UTC';
+ $value = timezone_name_get(date_timezone_get($date));
+ $this->assertEqual($expected, $value, "The current timezone should be $expected, found $value.");
+ $expected = '0';
+ $value = date_offset_get($date);
+ $this->assertEqual($expected, $value, "The current offset should be $expected, found $value.");
+
+ // Create date object from datetime string and convert it to a local date.
+ $input = '1970-01-01 00:00:00';
+ $timezone = 'UTC';
+ $date = date_make_date($input, $timezone);
+ $value = date_format($date, 'c');
+ $expected = '1970-01-01T00:00:00+00:00';
+ $this->assertEqual($expected, $value, "Test date_make_date('$input', '$timezone'): should be $expected, found $value.");
+
+ $expected = 'UTC';
+ $value = timezone_name_get(date_timezone_get($date));
+ $this->assertEqual($expected, $value, "The current timezone is $value: should be $expected.");
+ $expected = 0;
+ $value = date_offset_get($date);
+ $this->assertEqual($expected, $value, "The current offset is $value: should be $expected.");
+
+ $timezone = 'America/Los_Angeles';
+ date_timezone_set($date, timezone_open($timezone));
+ $value = date_format($date, 'c');
+ $expected = '1969-12-31T16:00:00-08:00';
+ $this->assertEqual($expected, $value, "Test date_timezone_set(timezone_open($timezone)): should be $expected, found $value.");
+
+ $expected = 'America/Los_Angeles';
+ $value = timezone_name_get(date_timezone_get($date));
+ $this->assertEqual($expected, $value, "The current timezone should be $expected, found $value.");
+ $expected = '-28800';
+ $value = date_offset_get($date);
+ $this->assertEqual($expected, $value, "The current offset should be $expected, found $value.");
+
+ // Convert the local version of a datetime string to UTC.
+ $input = '1969-12-31 16:00:00';
+ $timezone = 'America/Los_Angeles';
+ $date = date_make_date($input, $timezone);
+ $offset = date_offset_get($date);
+ $value = date_format($date, 'c');
+ $expected = '1969-12-31T16:00:00-08:00';
+ $this->assertEqual($expected, $value, "Test date_make_date('$input', '$timezone'): should be $expected, found $value.");
+
+ $expected = 'America/Los_Angeles';
+ $value = timezone_name_get(date_timezone_get($date));
+ $this->assertEqual($expected, $value, "The current timezone should be $expected, found $value.");
+ $expected = '-28800';
+ $value = date_offset_get($date);
+ $this->assertEqual($expected, $value, "The current offset should be $expected, found $value.");
+
+ $timezone = 'UTC';
+ date_timezone_set($date, timezone_open($timezone));
+ $value = date_format($date, 'c');
+ $expected = '1970-01-01T00:00:00+00:00';
+ $this->assertEqual($expected, $value, "Test date_timezone_set(\$date, timezone_open($timezone)): should be $expected, found $value.");
+
+ $expected = 'UTC';
+ $value = timezone_name_get(date_timezone_get($date));
+ $this->assertEqual($expected, $value, "The current timezone should be $expected, found $value.");
+ $expected = '0';
+ $value = date_offset_get($date);
+ $this->assertEqual($expected, $value, "The current offset should be $expected, found $value.");
+
+ // Create year-only date.
+ $input = '2009-00-00T00:00:00';
+ $timezone = NULL;
+ $granularity = array('year');
+ $date = date_make_date($input, $timezone, DATE_DATETIME, $granularity);
+ $value = date_format($date, 'Y');
+ $expected = '2009';
+ $this->assertEqual($expected, $value, "Test date_make_date($input, $timezone, DATE_DATETIME, array('year')): should be $expected, found $value.");
+
+ // Create month and year-only date.
+ $input = '2009-10-00T00:00:00';
+ $timezone = NULL;
+ $granularity = array('year', 'month');
+ $date = date_make_date($input, $timezone, DATE_DATETIME, $granularity);
+ $value = date_format($date, 'Y-m');
+ $expected = '2009-10';
+ $this->assertEqual($expected, $value, "Test date_make_date($input, $timezone, DATE_DATETIME, array('year', 'month')): should be $expected, found $value.");
+
+ // Create time-only date.
+ $input = '0000-00-00T10:30:00';
+ $timezone = NULL;
+ $granularity = array('hour', 'minute', 'second');
+ $date = date_make_date($input, $timezone, DATE_DATETIME, $granularity);
+ $value = date_format($date, 'H:i:s');
+ $expected = '10:30:00';
+ $this->assertEqual($expected, $value, "Test date_make_date($input, $timezone, DATE_DATETIME, array('hour', 'minute', 'second')): should be $expected, found $value.");
+
+ // Test date ranges.
+ $valid = array(
+ '-20:+20',
+ '-1:+0',
+ '-10:-5',
+ '2000:2020',
+ '-10:2010',
+ '1980:-10',
+ '1920:+20',
+ );
+ $invalid = array(
+ 'abc',
+ 'abc:+20',
+ '1920:+20a',
+ '+-20:+-30',
+ '12:12',
+ '0:+20',
+ '-20:0',
+ );
+ foreach ($valid as $range) {
+ $this->assertTrue(date_range_valid($range), "$range recognized as a valid date range.");
+ }
+ foreach ($invalid as $range) {
+ $this->assertFalse(date_range_valid($range), "$range recognized as an invalid date range.");
+ }
+
+ }
+
+ /**
+ * Implementation of tearDown().
+ */
+ function tearDown() {
+ variable_del('date_first_day');
+ variable_del('date_api_use_iso8601');
+ parent::tearDown();
+ }
+}
diff --git a/sites/all/modules/date/tests/date_repeat.test b/sites/all/modules/date/tests/date_repeat.test
new file mode 100644
index 0000000..9a93530
--- /dev/null
+++ b/sites/all/modules/date/tests/date_repeat.test
@@ -0,0 +1,447 @@
+ t('Date repeat calculations'),
+ 'description' => t('Test Date Repeat processes to create arrays of dates from iCal rules.') ,
+ 'group' => t('Date'),
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ function setUp() {
+ // Load the date_repeat module.
+ parent::setUp('date_api', 'date_timezone', 'date_repeat', 'jquery_ui');
+ }
+
+ public function testDateRepeat() {
+ require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_ical.inc');
+ require_once('./'. drupal_get_path('module', 'date_repeat') .'/date_repeat_calc.inc');
+ // Examples adapted from http://www.faqs.org/rfcs/rfc2445.html and
+ // http://www.kanzaki.com/docs/ical/rrule.html.
+
+ // Daily for 10 occurrences:
+ $start = "1997-09-02 09:00:00";
+ $end = "1997-09-30 09:00:00";
+ $rule = "RRULE:FREQ=DAILY;COUNT=10";
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ // should be (1997 9:00 AM EDT)September 2-11
+ $shouldbe = '1997-09-02 09:00:00, 1997-09-03 09:00:00, 1997-09-04 09:00:00, 1997-09-05 09:00:00, 1997-09-06 09:00:00, 1997-09-07 09:00:00, 1997-09-08 09:00:00, 1997-09-09 09:00:00, 1997-09-10 09:00:00, 1997-09-11 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Daily until September 24, 1997:
+ $start = "1997-09-02 09:00:00";
+ $end = "1997-09-30 09:00:00";
+ $rule = "RRULE:FREQ=DAILY;UNTIL=19970924T000000Z";
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ // should be (1997 9:00 AM EDT)September 2-23
+ $shouldbe = '1997-09-02 09:00:00, 1997-09-03 09:00:00, 1997-09-04 09:00:00, 1997-09-05 09:00:00, 1997-09-06 09:00:00, 1997-09-07 09:00:00, 1997-09-08 09:00:00, 1997-09-09 09:00:00, 1997-09-10 09:00:00, 1997-09-11 09:00:00, 1997-09-12 09:00:00, 1997-09-13 09:00:00, 1997-09-14 09:00:00, 1997-09-15 09:00:00, 1997-09-16 09:00:00, 1997-09-17 09:00:00, 1997-09-18 09:00:00, 1997-09-19 09:00:00, 1997-09-20 09:00:00, 1997-09-21 09:00:00, 1997-09-22 09:00:00, 1997-09-23 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Every other day - until September 30:
+ $start = "1997-09-02 09:00:00";
+ $end = "1997-09-30 09:00:00";
+ $rule = "RRULE:FREQ=DAILY;INTERVAL=2";
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ // should be (1997 9:00 AM EDT)September2,4,6,8...24,26,28,30;
+ $shouldbe = '1997-09-02 09:00:00, 1997-09-04 09:00:00, 1997-09-06 09:00:00, 1997-09-08 09:00:00, 1997-09-10 09:00:00, 1997-09-12 09:00:00, 1997-09-14 09:00:00, 1997-09-16 09:00:00, 1997-09-18 09:00:00, 1997-09-20 09:00:00, 1997-09-22 09:00:00, 1997-09-24 09:00:00, 1997-09-26 09:00:00, 1997-09-28 09:00:00, 1997-09-30 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Every 10 days, 2 occurrences:
+ $start = "1997-09-02 09:00:00";
+ $end = "1997-09-30 09:00:00";
+ $rule = "RRULE:FREQ=DAILY;INTERVAL=10;COUNT=2";
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ // should be (1997 9:00 AM EDT)September 2,12
+ $shouldbe = '1997-09-02 09:00:00, 1997-09-12 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Weekly for 3 occurrences
+ $start = "1997-09-02 09:00:00";
+ $end = "1997-09-30 09:00:00";
+ $rule = "RRULE:FREQ=WEEKLY;COUNT=3";
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ // should be (1997 9:00 AM EDT)September 2,9,16
+ $shouldbe = '1997-09-02 09:00:00, 1997-09-09 09:00:00, 1997-09-16 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Weekly until September 24, 1997
+ $start = "1997-09-02 09:00:00";
+ $end = "1997-09-30 09:00:00";
+ $rule = "RRULE:FREQ=WEEKLY;UNTIL=19970924T000000Z";
+ // ==> (1997 9:00 AM EDT)September 2,9,16,23
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-09-02 09:00:00, 1997-09-09 09:00:00, 1997-09-16 09:00:00, 1997-09-23 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Every other week - forever:
+ $start = "1997-09-02 09:00:00";
+ $end = "1997-09-30 09:00:00";
+ $rule = "RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=SU";
+ // should be (1997 9:00 AM EDT)September 2,16,30
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-09-02 09:00:00, 1997-09-16 09:00:00, 1997-09-30 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Weekly on Tuesday and Thursday for 4 weeks:
+ $start = "1997-09-02 09:00:00";
+ $end = "1997-09-30 09:00:00";
+ $rule = "RRULE:FREQ=WEEKLY;COUNT=8;WKST=SU;BYDAY=TU,TH";
+ // should be(1997 9:00 AM EDT)September 2,4,9,11,16,18,23,25
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-09-02 09:00:00, 1997-09-04 09:00:00, 1997-09-09 09:00:00, 1997-09-11 09:00:00, 1997-09-16 09:00:00, 1997-09-18 09:00:00, 1997-09-23 09:00:00, 1997-09-25 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Every other week on Tuesday and Thursday, for 5 occurrences:
+ $start = "1997-09-02 09:00:00";
+ $end = "1997-09-30 09:00:00";
+ $rule = "RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=5;WKST=SU;BYDAY=TU,TH";
+ // should be (1997 9:00 AM EDT)September 2,4,16,18,30
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-09-02 09:00:00, 1997-09-04 09:00:00, 1997-09-16 09:00:00, 1997-09-18 09:00:00, 1997-09-30 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Every other week on Monday, Wednesday and Friday until September 24, 1997,
+ $start = "1997-09-02 09:00:00";
+ $end = "1997-09-30 09:00:00";
+ $rule = "RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=19970924T000000Z;WKST=SU;BYDAY=MO,WE,FR";
+ // should be (1997 9:00 AM EDT)September 2,3,5,15,17,19
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-09-02 09:00:00, 1997-09-03 09:00:00, 1997-09-05 09:00:00, 1997-09-15 09:00:00, 1997-09-17 09:00:00, 1997-09-19 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Monthly on the 1st Friday for 2 occurrences:
+ $start = "1997-09-05 09:00:00";
+ $end = "1997-10-31 09:00:00";
+ $rule = "RRULE:FREQ=MONTHLY;COUNT=2;BYDAY=1FR";
+ // should be (1997 9:00 AM EDT)September 5;October 3
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-09-05 09:00:00, 1997-10-03 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Monthly on the 1st Friday until December 24, 1997:
+ $start = "1997-09-05 09:00:00";
+ $end = "1998-10-01 09:00:00";
+ $rule = "RRULE:FREQ=MONTHLY;UNTIL=19971224T000000Z;BYDAY=1FR";
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-09-05 09:00:00, 1997-10-03 09:00:00, 1997-11-07 09:00:00, 1997-12-05 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Every other month on the 1st and last Sunday of the month for 10 occurrences:
+ $start = "1997-09-07 09:00:00";
+ $end = "1998-10-01 09:00:00";
+ $rule = "RRULE:FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU";
+ // ==> (1997 9:00 AM EDT)September 7,28
+ // (1997 9:00 AM EST)November 2,30
+ // (1998 9:00 AM EST)January 4,25;March 1,29
+ // (1998 9:00 AM EDT)May 3,31
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-09-07 09:00:00, 1997-09-28 09:00:00, 1997-11-02 09:00:00, 1997-11-30 09:00:00, 1998-01-04 09:00:00, 1998-01-25 09:00:00, 1998-03-01 09:00:00, 1998-03-29 09:00:00, 1998-05-03 09:00:00, 1998-05-31 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Monthly on the second to last Monday of the month for 6 months:
+ $start = "1997-09-22 09:00:00";
+ $end = "1998-10-01 09:00:00";
+ $rule = "RRULE:FREQ=MONTHLY;COUNT=6;BYDAY=-2MO";
+ //==> (1997 9:00 AM EDT)September 22;October 20
+ // (1997 9:00 AM EST)November 17;December 22
+ // (1998 9:00 AM EST)January 19;February 16
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-09-22 09:00:00, 1997-10-20 09:00:00, 1997-11-17 09:00:00, 1997-12-22 09:00:00, 1998-01-19 09:00:00, 1998-02-16 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Every Tuesday, every other month:
+ $start = "1997-09-02 09:00:00";
+ $end = "1998-02-01 09:00:00";
+ $rule = "RRULE:FREQ=MONTHLY;INTERVAL=2;BYDAY=TU";
+ // ==> (1997 9:00 AM EDT)September 2,9,16,23,30
+ // (1997 9:00 AM EST)November 4,11,18,25
+ // (1998 9:00 AM EST)January 6,13,20,27;March 3,10,17,24,31
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-09-02 09:00:00, 1997-09-09 09:00:00, 1997-09-16 09:00:00, 1997-09-23 09:00:00, 1997-09-30 09:00:00, 1997-11-04 09:00:00, 1997-11-11 09:00:00, 1997-11-18 09:00:00, 1997-11-25 09:00:00, 1998-01-06 09:00:00, 1998-01-13 09:00:00, 1998-01-20 09:00:00, 1998-01-27 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Yearly in June and July for 10 occurrences:
+ $start = "1997-06-10 09:00:00";
+ $end = "2002-01-01 09:00:00";
+ $rule = "RRULE:FREQ=YEARLY;COUNT=10;BYMONTH=6,7";
+ // ==> (1997 9:00 AM EDT)June 10;July 10
+ // (1998 9:00 AM EDT)June 10;July 10
+ // (1999 9:00 AM EDT)June 10;July 10
+ // (2000 9:00 AM EDT)June 10;July 10
+ // (2001 9:00 AM EDT)June 10;July 10
+ // Note: Since none of the BYDAY, BYMONTHDAY or BYYEARDAY components
+ // are specified, the day is gotten from DTSTART
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-06-10 09:00:00, 1997-07-10 09:00:00, 1998-06-10 09:00:00, 1998-07-10 09:00:00, 1999-06-10 09:00:00, 1999-07-10 09:00:00, 2000-06-10 09:00:00, 2000-07-10 09:00:00, 2001-06-10 09:00:00, 2001-07-10 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Every other year on January, February, and March for 10 occurrences:
+ $start = "1997-03-10 09:00:00";
+ $end = "2004-01-01 09:00:00";
+ $rule = "RRULE:FREQ=YEARLY;INTERVAL=2;COUNT=10;BYMONTH=1,2,3";
+ // ==> (1997 9:00 AM EST)March 10
+ // (1999 9:00 AM EST)January 10;February 10;March 10
+ // (2001 9:00 AM EST)January 10;February 10;March 10
+ // (2003 9:00 AM EST)January 10;February 10;March 10
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-03-10 09:00:00, 1999-01-10 09:00:00, 1999-02-10 09:00:00, 1999-03-10 09:00:00, 2001-01-10 09:00:00, 2001-02-10 09:00:00, 2001-03-10 09:00:00, 2003-01-10 09:00:00, 2003-02-10 09:00:00, 2003-03-10 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //An example where the days generated makes a difference because of WKST:
+ $start = "1997-08-05 09:00:00";
+ $end = "2004-01-01 09:00:00";
+ $rule = "RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=MO";
+ // ==> (1997 EDT)Aug 5,10,19,24
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-08-05 09:00:00, 1997-08-10 09:00:00, 1997-08-19 09:00:00, 1997-08-24 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //changing only WKST from MO to SU, yields different results...
+ $start = "1997-08-05 09:00:00";
+ $end = "2004-01-01 09:00:00";
+ $rule = "RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=SU";
+ // Result: 1997 EDT August 5,17,19,31;
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-08-05 09:00:00, 1997-08-17 09:00:00, 1997-08-19 09:00:00, 1997-08-31 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Every 18 months on the 10th thru 15th of the month for 10 occurrences:
+ $start = "1997-09-10 09:00:00";
+ $end = "2004-01-01 09:00:00";
+ $rule = "RRULE:FREQ=MONTHLY;INTERVAL=18;COUNT=10;BYMONTHDAY=10,11,12,13,14,15";
+ // ==> (1997 9:00 AM EDT)September 10,11,12,13,14,15
+ // (1999 9:00 AM EST)March 10,11,12,13
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-09-10 09:00:00, 1997-09-11 09:00:00, 1997-09-12 09:00:00, 1997-09-13 09:00:00, 1997-09-14 09:00:00, 1997-09-15 09:00:00, 1999-03-10 09:00:00, 1999-03-11 09:00:00, 1999-03-12 09:00:00, 1999-03-13 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Monthly on the third to the last day of the month, forever:
+ $start = "1997-09-28 09:00:00";
+ $end = "1998-03-01 09:00:00";
+ $rule = "RRULE:FREQ=MONTHLY;BYMONTHDAY=-3";
+ // ==> (1997 9:00 AM EDT)September 28
+ // (1997 9:00 AM EST)October 29;November 28;December 29
+ // (1998 9:00 AM EST)January 29;February 26
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-09-28 09:00:00, 1997-10-29 09:00:00, 1997-11-28 09:00:00, 1997-12-29 09:00:00, 1998-01-29 09:00:00, 1998-02-26 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Every Thursday in March, forever:
+ // ==> (1997 9:00 AM EST)March 13,20,27
+ // (1998 9:00 AM EST)March 5,12,19,26
+ // (1999 9:00 AM EST)March 4,11,18,25
+ $start = "1997-03-13 09:00:00";
+ $end = "1999-03-31 09:00:00";
+ $rule = "RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=TH";
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-03-13 09:00:00, 1997-03-20 09:00:00, 1997-03-27 09:00:00, 1998-03-05 09:00:00, 1998-03-12 09:00:00, 1998-03-19 09:00:00, 1998-03-26 09:00:00, 1999-03-04 09:00:00, 1999-03-11 09:00:00, 1999-03-18 09:00:00, 1999-03-25 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Every Thursday, but only during June, July, and August, forever:
+ // ==> (1997 9:00 AM EDT)June 5,12,19,26;July 3,10,17,24,31;August 7,14,21,28
+ // (1998 9:00 AM EDT)June 4,11,18,25;July 2,9,16,23,30;August 6,13,20,27
+ // (1999 9:00 AM EDT)June 3,10,17,24;July 1,8,15,22,29;August 5,12,19,26
+ $start = "1997-06-05 09:00:00";
+ $end = "1999-08-31 09:00:00";
+ $rule = "RRULE:FREQ=YEARLY;BYDAY=TH;BYMONTH=6,7,8";
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-06-05 09:00:00, 1997-06-12 09:00:00, 1997-06-19 09:00:00, 1997-06-26 09:00:00, 1997-07-03 09:00:00, 1997-07-10 09:00:00, 1997-07-17 09:00:00, 1997-07-24 09:00:00, 1997-07-31 09:00:00, 1997-08-07 09:00:00, 1997-08-14 09:00:00, 1997-08-21 09:00:00, 1997-08-28 09:00:00, 1998-06-04 09:00:00, 1998-06-11 09:00:00, 1998-06-18 09:00:00, 1998-06-25 09:00:00, 1998-07-02 09:00:00, 1998-07-09 09:00:00, 1998-07-16 09:00:00, 1998-07-23 09:00:00, 1998-07-30 09:00:00, 1998-08-06 09:00:00, 1998-08-13 09:00:00, 1998-08-20 09:00:00, 1998-08-27 09:00:00, 1999-06-03 09:00:00, 1999-06-10 09:00:00, 1999-06-17 09:00:00, 1999-06-24 09:00:00, 1999-07-01 09:00:00, 1999-07-08 09:00:00, 1999-07-15 09:00:00, 1999-07-22 09:00:00, 1999-07-29 09:00:00, 1999-08-05 09:00:00, 1999-08-12 09:00:00, 1999-08-19 09:00:00, 1999-08-26 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Monthly on the 2nd and 15th of the month for 10 occurrences:
+ // ==> (1997 9:00 AM EDT)September 2,15;October 2,15
+ // (1997 9:00 AM EST)November 2,15;December 2,15
+ // (1998 9:00 AM EST)January 2,15
+ $start = "1997-09-02 09:00:00";
+ $end = "1998-01-31 09:00:00";
+ $rule = "RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=2,15";
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-09-02 09:00:00, 1997-09-15 09:00:00, 1997-10-02 09:00:00, 1997-10-15 09:00:00, 1997-11-02 09:00:00, 1997-11-15 09:00:00, 1997-12-02 09:00:00, 1997-12-15 09:00:00, 1998-01-02 09:00:00, 1998-01-15 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Monthly on the first and last day of the month for 10 occurrences:
+ // ==> (1997 9:00 AM EDT)September 30;October 1
+ // (1997 9:00 AM EST)October 31;November 1,30;December 1,31
+ // (1998 9:00 AM EST)January 1,31;February 1
+ $start = "1997-09-30 09:00:00";
+ $end = "1998-03-31 09:00:00";
+ $rule = "RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1";
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-09-30 09:00:00, 1997-10-01 09:00:00, 1997-10-31 09:00:00, 1997-11-01 09:00:00, 1997-11-30 09:00:00, 1997-12-01 09:00:00, 1997-12-31 09:00:00, 1998-01-01 09:00:00, 1998-01-31 09:00:00, 1998-02-01 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Every Friday the 13th, forever:
+ $rule = "EXDATE;TZID=US-Eastern:19970902T090000";
+ // ==> (1998 9:00 AM EST)February 13;March 13;November 13
+ // (1999 9:00 AM EDT)August 13
+ // (2000 9:00 AM EDT)October 13
+ $start = "1997-09-02 09:00:00";
+ $end = "2000-12-31 09:00:00";
+ $rule = "RRULE:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13";
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-09-02 09:00:00, 1998-02-13 09:00:00, 1998-03-13 09:00:00, 1998-11-13 09:00:00, 1999-08-13 09:00:00, 2000-10-13 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //The first Saturday that follows the first Sunday of the month, forever:
+ // ==> (1997 9:00 AM EDT)September 13;October 11
+ // (1997 9:00 AM EST)November 8;December 13
+ // (1998 9:00 AM EST)January 10;February 7;March 7
+ // (1998 9:00 AM EDT)April 11;May 9;June 13...
+ $start = "1997-09-13 09:00:00";
+ $end = "1998-06-30 09:00:00";
+ $rule = "RRULE:FREQ=MONTHLY;BYDAY=SA;BYMONTHDAY=7,8,9,10,11,12,13";
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-09-13 09:00:00, 1997-10-11 09:00:00, 1997-11-08 09:00:00, 1997-12-13 09:00:00, 1998-01-10 09:00:00, 1998-02-07 09:00:00, 1998-03-07 09:00:00, 1998-04-11 09:00:00, 1998-05-09 09:00:00, 1998-06-13 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Every four years, the first Tuesday after a Monday in November,
+ //forever (U.S. Presidential Election day):
+ // ==> (1996 9:00 AM EST)November 5
+ // (2000 9:00 AM EST)November 7
+ // (2004 9:00 AM EST)November 2
+ $start = "1996-11-05 09:00:00";
+ $end = "2004-11-30 09:00:00";
+ $rule = "RRULE:FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,5,6,7,8";
+ $shouldbe = '1996-11-05 09:00:00, 2000-11-07 09:00:00, 2004-11-02 09:00:00';
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Every 20th Monday of the year, forever:
+ $start = "1997-05-19 09:00:00";
+ $end = "2000-01-01 09:00:00";
+ $rule = "RRULE:FREQ=YEARLY;BYDAY=20MO";
+ // ==> (1997 9:00 AM EDT)May 19
+ // (1998 9:00 AM EDT)May 18
+ // (1999 9:00 AM EDT)May 17
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-05-19 09:00:00, 1998-05-18 09:00:00, 1999-05-17 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+ //Every Sunday in January, every other year, forever:
+ $start = "1997-01-05 09:00:00";
+ $end = "2001-02-01 09:00:00";
+ $rule = 'RRULE:FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU';
+ // ==> (1997 9:00 AM EDT)January 5,12,19,26
+ // (1999 9:00 AM EDT)January 3,10,17,24,31
+ // (2001 9:00 AM EDT)January 7,14,21,28
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '1997-01-05 09:00:00, 1997-01-12 09:00:00, 1997-01-19 09:00:00, 1997-01-26 09:00:00, 1999-01-03 09:00:00, 1999-01-10 09:00:00, 1999-01-17 09:00:00, 1999-01-24 09:00:00, 1999-01-31 09:00:00, 2001-01-07 09:00:00, 2001-01-14 09:00:00, 2001-01-21 09:00:00, 2001-01-28 09:00:00';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+return;
+
+ //Every Thanksgiving, forever:
+ $start = "1997-01-01 09:00:00";
+ $end = "2001-02-01 09:00:00";
+ $rule = 'RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=11;BYDAY=4TH';
+ // ==> (1997 9:00 AM EDT)Nov
+ // (1999 9:00 AM EDT)Nov
+ // (2001 9:00 AM EDT)Nov
+ $dates = date_repeat_calc($rule, $start, $end, array());
+ $shouldbe = '';
+ $result = implode(', ', $dates);
+ $this->assertEqual($result, $shouldbe, $rule .'; Starting '. $start .'; results: '. $result);
+
+// TODO:
+// BYYEARDAY, BYSETPOS,
+// BYHOUR, BYMINUTE, HOURLY, MINUTELY, SECONDLY
+// have not yet been implemented in date_repeat.
+
+//Every 3rd year on the 1st, 100th and 200th day for 10 occurrences:
+$date = "DTSTART;TZID=US-Eastern:19970101T090000";
+$rule = "RRULE:FREQ=YEARLY;INTERVAL=3;COUNT=10;BYYEARDAY=1,100,200";
+// ==> (1997 9:00 AM EST)January 1
+// (1997 9:00 AM EDT)April 10;July 19
+// (2000 9:00 AM EST)January 1
+// (2000 9:00 AM EDT)April 9;July 18
+// (2003 9:00 AM EST)January 1
+// (2003 9:00 AM EDT)April 10;July 19
+// (2006 9:00 AM EST)January 1
+
+//Monday of week number 20 (where the default start of the week is Monday), forever:
+$date = "DTSTART;TZID=US-Eastern:19970512T090000";
+$rule = "RRULE:FREQ=YEARLY;BYWEEKNO=20;BYDAY=MO";
+// ==> (1997 9:00 AM EDT)May 12
+// (1998 9:00 AM EDT)May 11
+// (1999 9:00 AM EDT)May 17
+
+//The 3rd instance into the month of one of Tuesday, Wednesday or
+//Thursday, for the next 3 months:
+$date = "DTSTART;TZID=US-Eastern:19970904T090000";
+$rule = "RRULE:FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3";
+// ==> (1997 9:00 AM EDT)September 4;October 7
+// (1997 9:00 AM EST)November 6
+
+//The 2nd to last weekday of the month:
+$date = "DTSTART;TZID=US-Eastern:19970929T090000";
+$rule = "RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2";
+// ==> (1997 9:00 AM EDT)September 29
+// (1997 9:00 AM EST)October 30;November 27;December 30
+// (1998 9:00 AM EST)January 29;February 26;March 30
+
+//Every 3 hours from 9:00 AM to 5:00 PM on a specific day:
+$date = "DTSTART;TZID=US-Eastern:19970902T090000";
+$rule = "RRULE:FREQ=HOURLY;INTERVAL=3;UNTIL=19970902T170000Z";
+// ==> (September 2, 1997 EDT)09:00,12:00,15:00
+
+//Every 15 minutes for 6 occurrences:
+$date = "DTSTART;TZID=US-Eastern:19970902T090000";
+$rule = "RRULE:FREQ=MINUTELY;INTERVAL=15;COUNT=6";
+// ==> (September 2, 1997 EDT)09:00,09:15,09:30,09:45,10:00,10:15
+
+//Every hour and a half for 4 occurrences:
+$date = "DTSTART;TZID=US-Eastern:19970902T090000";
+$rule = "RRULE:FREQ=MINUTELY;INTERVAL=90;COUNT=4";
+// ==> (September 2, 1997 EDT)09:00,10:30;12:00;13:30
+
+//Every 20 minutes from 9:00 AM to 4:40 PM every day:
+$date = "DTSTART;TZID=US-Eastern:19970902T090000";
+$rule = "RRULE:FREQ=DAILY;BYHOUR=9,10,11,12,13,14,15,16;BYMINUTE=0,20,40";
+// or
+$rule = "RRULE:FREQ=MINUTELY;INTERVAL=20;BYHOUR=9,10,11,12,13,14,15,16";
+// ==> (September 2, 1997 EDT)9:00,9:20,9:40,10:00,10:20,16:00,16:20,16:40
+// (September 3, 1997 EDT)9:00,9:20,9:40,10:00,10:20,16:00,16:20,16:40
+
+ }
+}
\ No newline at end of file
diff --git a/sites/all/modules/date/tests/rrule.ics b/sites/all/modules/date/tests/rrule.ics
new file mode 100644
index 0000000..285831c
--- /dev/null
+++ b/sites/all/modules/date/tests/rrule.ics
@@ -0,0 +1,125 @@
+BEGIN:VCALENDAR
+PRODID:-//Test
+VERSION:2.0
+X-WR-CALDESC:Test various iCal RRULEs.
+BEGIN:VEVENT
+UID:iCalRRuleTest1
+SUMMARY:Daily for 10 occurrences
+DTSTART;TZID=US-Eastern:20090702T090000
+RRULE:FREQ=DAILY;COUNT=10
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest2
+SUMMARY:Daily until December 24, 2009
+DTSTART;TZID=US-Eastern:20091202T090000
+RRULE:FREQ=DAILY;UNTIL=20091224T000000Z
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest3
+SUMMARY:Every other day
+DTSTART;TZID=US-Eastern:20090202T090000
+RRULE:FREQ=DAILY;INTERVAL=2
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest4
+SUMMARY:Every 10 days, 5 occurrences
+DTSTART;TZID=US-Eastern:20090302T090000
+RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest5
+SUMMARY:Everyday in January, for 2 years
+DTSTART;TZID=US-Eastern:20090101T090000
+RRULE:FREQ=YEARLY;UNTIL=20110131T090000Z;BYMONTH=1;BYDAY=SU,MO,TU,WE,TH,FR,SA
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest6
+SUMMARY:Weekly for 10 occurrences
+DTSTART;TZID=US-Eastern:20090102T090000
+RRULE:FREQ=WEEKLY;COUNT=10
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest7
+SUMMARY:Weekly on Tuesday and Thursday for 5 weeks
+DTSTART;TZID=US-Eastern:20090902T090000
+RRULE:FREQ=WEEKLY;UNTIL=20091007T000000Z;WKST=SU;BYDAY=TU,TH
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest8
+SUMMARY:Every other week on Monday, Wednesday and Friday until December 24, 2009:
+DTSTART;TZID=US-Eastern:20090502T090000
+RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=20091224T000000Z;WKST=SU;BYDAY=MO,WE,FR
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest9
+SUMMARY:Every other week on Tuesday and Thursday, for 8 occurrences
+DTSTART;TZID=US-Eastern:20090702T090000
+RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=8;WKST=SU;BYDAY=TU,TH
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest10
+SUMMARY:Monthly on the 1st Friday for ten occurrences
+DTSTART;TZID=US-Eastern:20090905T090000
+RRULE:FREQ=MONTHLY;COUNT=10;BYDAY=1FR
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest11
+SUMMARY:Monthly on the 1st Friday until December 24, 2009
+DTSTART;TZID=US-Eastern:20090905T090000
+RRULE:FREQ=MONTHLY;UNTIL=20091224T000000Z;BYDAY=1FR
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest12
+SUMMARY:Every other month on the 1st and last Sunday of the month for 10 occurrences
+DTSTART;TZID=US-Eastern:20090907T090000
+RRULE:FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest13
+SUMMARY:Monthly on the second to last Monday of the month for 6 months
+DTSTART;TZID=US-Eastern:20090119T090000
+RRULE:FREQ=MONTHLY;COUNT=6;BYDAY=-2MO
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest14
+SUMMARY:Monthly on the third to the last day of the month
+DTSTART;TZID=US-Eastern:20090928T090000
+RRULE:FREQ=MONTHLY;BYMONTHDAY=-3
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest15
+SUMMARY:Monthly on the 2nd and 15th of the month for 10 occurrences
+DTSTART;TZID=US-Eastern:20090202T090000
+RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=2,15
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest16
+SUMMARY:Monthly on the first and last day of the month for 10 occurrences
+DTSTART;TZID=US-Eastern:20090130T090000
+RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest17
+SUMMARY:Every 3 months on the 10th thru 15th of the month for 10 occurrences
+DTSTART;TZID=US-Eastern:20090410T090000
+RRULE:FREQ=MONTHLY;INTERVAL=3;COUNT=10;BYMONTHDAY=10,11,12,13,14,15
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest18
+SUMMARY:Every Tuesday, every other month
+DTSTART;TZID=US-Eastern:20090602T090000
+RRULE:FREQ=MONTHLY;INTERVAL=2;BYDAY=TU
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest19
+SUMMARY:Yearly in June and July for 10 occurrences
+DTSTART;TZID=US-Eastern:20090610T090000
+RRULE:FREQ=YEARLY;COUNT=10;BYMONTH=6,7
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest20
+SUMMARY:Every Thursday in March
+DTSTART;TZID=US-Eastern:20090305T090000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=TH
+END:VEVENT
+END:VCALENDAR
\ No newline at end of file
diff --git a/sites/all/modules/date/theme/date-navigation.tpl.php b/sites/all/modules/date/theme/date-navigation.tpl.php
new file mode 100644
index 0000000..e512413
--- /dev/null
+++ b/sites/all/modules/date/theme/date-navigation.tpl.php
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sites/all/modules/date/theme/date-valarm.tpl.php b/sites/all/modules/date/theme/date-valarm.tpl.php
new file mode 100644
index 0000000..08f8adf
--- /dev/null
+++ b/sites/all/modules/date/theme/date-valarm.tpl.php
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sites/all/modules/date/theme/theme.inc b/sites/all/modules/date/theme/theme.inc
new file mode 100644
index 0000000..14abfa1
--- /dev/null
+++ b/sites/all/modules/date/theme/theme.inc
@@ -0,0 +1,417 @@
+args;
+ $prev_args = $view->args;
+ $pos = $view->date_info->date_arg_pos;
+ $min_date = is_object($view->date_info->min_date) ? $view->date_info->min_date : date_now();
+ $max_date = is_object($view->date_info->max_date) ? $view->date_info->max_date : date_now();
+
+ if (empty($view->date_info->hide_nav)) {
+ $prev_date = drupal_clone($min_date);
+ date_modify($prev_date, '-1 '. $view->date_info->granularity);
+ $next_date = drupal_clone($min_date);
+ date_modify($next_date, '+1 '. $view->date_info->granularity);
+ $format = array('year' => 'Y', 'month' => 'Y-m', 'day' => 'Y-m-d');
+ switch ($view->date_info->granularity) {
+ case 'week':
+ $next_week = date_week(date_format($next_date, 'Y-m-d'));
+ $prev_week = date_week(date_format($prev_date, 'Y-m-d'));
+ $next_arg = date_format($next_date, 'Y-\W') . $next_week;
+ $prev_arg = date_format($prev_date, 'Y-\W') . $prev_week;
+ break;
+ default:
+ $next_arg = date_format($next_date, $format[$view->date_info->granularity]);
+ $prev_arg = date_format($prev_date, $format[$view->date_info->granularity]);
+ }
+ $next_path = str_replace($view->date_info->date_arg, $next_arg, $view->date_info->url);
+ $prev_path = str_replace($view->date_info->date_arg, $prev_arg, $view->date_info->url);
+ $next_args[$pos] = $next_arg;
+ $prev_args[$pos] = $prev_arg;
+ $vars['next_url'] = date_real_url($view, NULL, $next_arg);
+ $vars['prev_url'] = date_real_url($view, NULL, $prev_arg);
+ $vars['next_options'] = $vars['prev_options'] = array();
+ }
+ else {
+ $next_path = '';
+ $prev_path = '';
+ $vars['next_url'] = '';
+ $vars['prev_url'] = '';
+ $vars['next_options'] = $vars['prev_options'] = array();
+ }
+
+ // Check whether navigation links would point to
+ // a date outside the allowed range.
+ if (!empty($next_date) && !empty($vars['next_url']) && date_format($next_date, 'Y') > $view->date_info->max_allowed_year) {
+ $vars['next_url'] = '';
+ }
+ if (!empty($prev_date) && !empty($vars['prev_url']) && date_format($prev_date, 'Y') < $view->date_info->min_allowed_year) {
+ $vars['prev_url'] = '';
+ }
+
+ $vars['prev_options'] += array('attributes' => array());
+ $vars['next_options'] += array('attributes' => array());
+ $prev_title = '';
+ $next_title = '';
+
+ // Build next/prev link titles.
+ switch ($view->date_info->granularity) {
+ case 'year':
+ $prev_title = t('Navigate to previous year');
+ $next_title = t('Navigate to next year');
+ break;
+ case 'month':
+ $prev_title = t('Navigate to previous month');
+ $next_title = t('Navigate to next month');
+ break;
+ case 'week':
+ $prev_title = t('Navigate to previous week');
+ $next_title = t('Navigate to next week');
+ break;
+ case 'day':
+ $prev_title = t('Navigate to previous day');
+ $next_title = t('Navigate to next day');
+ break;
+ }
+ $vars['prev_options']['attributes'] += array('title' => $prev_title);
+ $vars['next_options']['attributes'] += array('title' => $next_title);
+
+ // Add nofollow for next/prev links.
+ $vars['prev_options']['attributes'] += array('rel' => 'nofollow');
+ $vars['next_options']['attributes'] += array('rel' => 'nofollow');
+
+ $link = FALSE;
+ // Month navigation titles are used as links in the block view.
+ if (!empty($view->date_info->block) && $view->date_info->granularity == 'month') {
+ $link = TRUE;
+ }
+
+ $nav_title = theme('date_nav_title', $view->date_info->granularity, $view, $link);
+ $vars['nav_title'] = $nav_title;
+ $vars['block'] = !empty($view->date_info->block);
+}
+
+/**
+ * Theme the calendar title
+ */
+function theme_date_nav_title($granularity, $view, $link = FALSE, $format = NULL) {
+ switch ($granularity) {
+ case 'year':
+ $title = $view->date_info->year;
+ $date_arg = $view->date_info->year;
+ break;
+ case 'month':
+ $format = !empty($format) ? $format : (empty($view->date_info->mini) ? 'F Y' : 'F');
+ $title = date_format_date($view->date_info->min_date, 'custom', $format);
+ $date_arg = $view->date_info->year .'-'. date_pad($view->date_info->month);
+ break;
+ case 'day':
+ $format = !empty($format) ? $format : (empty($view->date_info->mini) ? 'l, F j Y' : 'l, F j');
+ $title = date_format_date($view->date_info->min_date, 'custom', $format);
+ $date_arg = $view->date_info->year .'-'. date_pad($view->date_info->month) .'-'. date_pad($view->date_info->day);
+ break;
+ case 'week':
+ $format = !empty($format) ? $format : (empty($view->date_info->mini) ? 'F j Y' : 'F j');
+ $title = t('Week of @date', array('@date' => date_format_date($view->date_info->min_date, 'custom', $format)));
+ $date_arg = $view->date_info->year .'-W'. date_pad($view->date_info->week);
+ break;
+ }
+ if (!empty($view->date_info->mini) || $link) {
+ // Month navigation titles are used as links in the mini view.
+ $attributes = array('title' => t('View full page month'));
+ $url = date_real_url($view, $granularity, $date_arg, TRUE);
+ return l($title, $url, array('attributes' => $attributes));
+ }
+ else {
+ return $title;
+ }
+}
+
+/**
+ * Preprocessor to construct an ical vcalendar
+ *
+ * @param $events
+ * An array of events where each event is an array keyed on the uid:
+ * 'start'
+ * Start date object,
+ * 'end'
+ * End date object, optional, omit for all day event.
+ * 'summary'
+ * Title of event (Text)
+ * 'description'
+ * Description of event (Text)
+ * 'location'
+ * Location of event (Text or vvenue id)
+ * 'uid'
+ * ID of the event for use by calendaring program, usually the url of the node
+ * 'url'
+ * URL of event information
+ *
+ * 'alarm'
+ * sub-array of alarm information for the event, including:
+ * - 'action' - the action to take, either 'DISPLAY' or 'EMAIL'
+ * - 'trigger' - the time period for the trigger, like -P2D.
+ * - 'repeat' - the number of times to repeat the alarm.
+ * - 'duration' - the time period between repeated alarms, like P1D.
+ * - 'description' - the description of the alarm.
+ * An email alarm should have two additional parts:
+ * - 'email' - a comma-separated list of email recipients.
+ * - 'summary' - the subject of the alarm email.
+ *
+ * @param $calname
+ * Name of the calendar. Use site name if none is specified.
+ *
+ */
+function template_preprocess_date_vcalendar(&$vars) {
+
+ $vars['current_date'] = date_format(date_now(), DATE_FORMAT_ICAL);
+ $vars['current_date_utc'] = date_format(date_now('UTC'), DATE_FORMAT_ICAL);
+ $vars['site_timezone'] = date_default_timezone_name();
+ $vars['calname'] = date_ical_escape_text(!empty($vars['calname']) ? $vars['calname'] : variable_get('site_name', ''));
+
+ // Format the event results as iCal expects.
+ $events_in = $vars['events'];
+ $events = array();
+ $rows = $vars['rows'];
+ foreach ($events_in as $uid => $event) {
+ $row = array_shift($rows);
+ // Omit any items with empty dates.
+ if (!empty($event['start'])) {
+ $events[$uid] = $event;
+ $timezone = timezone_name_get(date_timezone_get($event['start']));
+ if (!empty($timezone)) {
+ $events[$uid]['timezone'] = "TZID=$timezone;";
+ }
+ else {
+ $events[$uid]['timezone'] = '';
+ }
+ $date_format = ($row->calendar_all_day == TRUE) ? DATE_FORMAT_ICAL_DATE : DATE_FORMAT_ICAL;
+ $events[$uid]['start'] = date_format($event['start'], $date_format);
+
+ // According to RFC 2445 (clarified in RFC 5545) the DTEND value is
+ // non-inclusive. When it is a DATE rather than a DATETIME, this means
+ // that we should add one day to its value.
+ if ($row->calendar_all_day) {
+ if (empty($event['end'])) {
+ $event['end'] = $event['start'];
+ }
+ date_modify($event['end'], "+1 day");
+ }
+
+ if ($event['start'] && $event['end']) {
+ $events[$uid]['end'] = date_format($event['end'], $date_format);
+ }
+ else {
+ $events[$uid]['end'] = $events[$uid]['start'];
+ }
+
+ foreach ($event as $key => $value) {
+ if (is_string($value)) {
+ $event[trim($key)] = trim($value);
+ }
+ }
+
+ // Escape text values.
+ foreach ($event as $key => $value) {
+ if ($key == 'alarm') {
+ foreach ($value as $alarm_key => $alarm_value) {
+ if (in_array($alarm_key, array('summary', 'description'))) {
+ $events[$uid]['alarm'][$alarm_key] = date_ical_escape_text($alarm_value);
+ }
+ }
+ }
+ elseif (in_array($key, array('summary', 'description', 'location'))) {
+ $events[$uid][$key] = date_ical_escape_text(html_entity_decode($value, ENT_QUOTES, 'UTF-8'));
+ }
+ }
+ }
+ }
+
+ $vars['events'] = $events;
+}
+
+/**
+ * Preprocessor for Date Views filter form.
+ */
+function template_preprocess_date_views_filter_form(&$vars) {
+ $form = $vars['form'];
+ $vars['date'] = drupal_render($form['valuedate']);
+ $vars['mindate'] = drupal_render($form['mindate']);
+ $vars['maxdate'] = drupal_render($form['maxdate']);
+ $vars['adjustment'] = drupal_render($form['valueadjustment']);
+ $vars['minadjustment'] = drupal_render($form['minadjustment']);
+ $vars['maxadjustment'] = drupal_render($form['maxadjustment']);
+ $vars['description'] = drupal_render($form['description']) . drupal_render($form);
+}
+
+/**
+ * Format a date timezone element.
+ *
+ * @param $element
+ * An associative array containing the properties of the element.
+ * Properties used: title, value, options, description, required and attributes.
+ * @return
+ * A themed HTML string representing the date selection boxes.
+ */
+function theme_date_timezone($element) {
+ return '
';
+}
+
+/**
+ * Format a date selection element.
+ *
+ * @param $element
+ * An associative array containing the properties of the element.
+ * Properties used: title, value, options, description, required and attributes.
+ * @return
+ * A themed HTML string representing the date selection boxes.
+ */
+function theme_date_select($element) {
+ $output = '';
+ $class = 'container-inline-date';
+ // Add #date_float to allow date parts to float together on the same line.
+ if (empty($element['#date_float'])) {
+ $class .= ' date-clear-block';
+ }
+ if (isset($element['#children'])) {
+ $output = $element['#children'];
+ }
+ return '
'. theme('form_element', $element, $output) .'
';
+}
+
+/**
+ * Format a date text element.
+ *
+ * @param $element
+ * An associative array containing the properties of the element.
+ * Properties used: title, value, options, description, required and attributes.
+ * @return
+ * A themed HTML string representing the date selection boxes.
+ */
+function theme_date_text($element) {
+ $output = '';
+ $class = 'container-inline-date';
+ // Add #date_float to allow date parts to float together on the same line.
+ if (empty($element['#date_float'])) {
+ $class .= ' date-clear-block';
+ }
+ if (isset($element['#children'])) {
+ $output = $element['#children'];
+ }
+ return '
'. theme('form_element', $element, $output) .'
';
+}
+
+/**
+ * Themes for date input form elements
+ */
+function theme_date_select_element($element) {
+ $part = array_pop($element['#parents']);
+ return '
';
+}
+
+/**
+ * Functions to separate date parts in form.
+ *
+ * Separators float up to the title level for elements with titles,
+ * so won't work if this element has titles above the element date parts.
+ */
+function theme_date_part_hour_prefix($element) {
+ if ($element['#date_label_position'] != 'above') {
+ return ' - ';
+ }
+}
+
+function theme_date_part_minsec_prefix($element) {
+ if ($element['#date_label_position'] != 'above') {
+ return ':';
+ }
+}
+
+/**
+ * Format labels for each date part in a date_select.
+ *
+ * @param $part_type
+ * the type of field used for this part, 'textfield' or 'select'
+ * @param $element
+ * An associative array containing the properties of the element.
+ * Properties used: title, value, options, description, required and attributes.
+ */
+function theme_date_part_label_year($part_type, $element) {
+ return date_t('Year', 'datetime');
+}
+function theme_date_part_label_month($part_type, $element) {
+ return date_t('Month', 'datetime');
+}
+function theme_date_part_label_day($part_type, $element) {
+ return date_t('Day', 'datetime');
+}
+function theme_date_part_label_hour($part_type, $element) {
+ return date_t('Hour', 'datetime');
+}
+function theme_date_part_label_minute($part_type, $element) {
+ return date_t('Minute', 'datetime');
+}
+function theme_date_part_label_second($part_type, $element) {
+ return date_t('Second', 'datetime');
+}
+function theme_date_part_label_ampm($part_type, $element) {
+ return ' ';
+}
+function theme_date_part_label_timezone($part_type, $element) {
+ return t('Timezone');
+}
+
+/**
+ * Theme for a date block that looks like a mini calendar day.
+ * Pass in a date object already set to the right timezone,
+ * format as a calendar page date. The calendar styling is created in css.
+ */
+function theme_date_calendar_day($date) {
+ if (empty($date)) {
+ return NULL;
+ }
+ return '