From: Andrey Kutejko Date: Fri, 29 Nov 2013 00:24:57 +0000 (+0200) Subject: date format X-Git-Tag: 0.1~5 X-Git-Url: https://git.andy128k.dev/?a=commitdiff_plain;h=8008bf636ca265ffaf4c69c1f6f55f5aba28269d;p=missing-tools.git date format --- diff --git a/composer.json b/composer.json index f716ed1..d4bfc76 100644 --- a/composer.json +++ b/composer.json @@ -11,8 +11,17 @@ "autoload": { "classmap" : ["src"] }, + "require": { + "andy128k/pegp": "dev-master" + }, "require-dev": { "phpunit/phpunit": "3.7.*" - } + }, + "repositories": [ + { + "type": "composer", + "url": "http://packages.andy128k.net/php/" + } + ] } diff --git a/composer.lock b/composer.lock index 70ea743..315cd27 100644 --- a/composer.lock +++ b/composer.lock @@ -3,23 +3,51 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "8c6ef015d9701af81af1ba6dec9f4ada", + "hash": "70d6aba0d7196c6999d2539c4ec24481", "packages": [ - + { + "name": "andy128k/pegp", + "version": "dev-master", + "source": { + "type": "git", + "url": "git://git.andy128k.net/pegp.git", + "reference": "52db5ee8c04ec7e411af0f73aa1e54ce208d08e0" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib" + ] + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Kutejko", + "email": "andy128k@gmail.com" + } + ], + "description": "PEG", + "time": "2013-08-11 11:10:38" + } ], "packages-dev": [ { "name": "phpunit/php-code-coverage", - "version": "1.2.12", + "version": "1.2.13", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "1.2.12" + "reference": "466e7cd2554b4e264c9e3f31216d25ac0e5f3d94" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.12", - "reference": "1.2.12", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/466e7cd2554b4e264c9e3f31216d25ac0e5f3d94", + "reference": "466e7cd2554b4e264c9e3f31216d25ac0e5f3d94", "shasum": "" }, "require": { @@ -67,20 +95,20 @@ "testing", "xunit" ], - "time": "2013-07-06 06:26:16" + "time": "2013-09-10 08:14:32" }, { "name": "phpunit/php-file-iterator", - "version": "1.3.3", + "version": "1.3.4", "source": { "type": "git", - "url": "git://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "1.3.3" + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" }, "dist": { "type": "zip", - "url": "https://github.com/sebastianbergmann/php-file-iterator/zipball/1.3.3", - "reference": "1.3.3", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", "shasum": "" }, "require": { @@ -107,12 +135,12 @@ } ], "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "http://www.phpunit.de/", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", "keywords": [ "filesystem", "iterator" ], - "time": "2012-10-11 04:44:38" + "time": "2013-10-10 15:34:57" }, { "name": "phpunit/php-text-template", @@ -204,16 +232,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "1.2.0" + "reference": "5220af2a7929aa35cf663d97c89ad3d50cf5fa3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1.2.0", - "reference": "1.2.0", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/5220af2a7929aa35cf663d97c89ad3d50cf5fa3e", + "reference": "5220af2a7929aa35cf663d97c89ad3d50cf5fa3e", "shasum": "" }, "require": { @@ -250,20 +278,20 @@ "keywords": [ "tokenizer" ], - "time": "2013-08-04 05:57:48" + "time": "2013-09-13 04:58:23" }, { "name": "phpunit/phpunit", - "version": "3.7.24", + "version": "3.7.28", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "3.7.24" + "reference": "3b97c8492bcafbabe6b6fbd2ab35f2f04d932a8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.24", - "reference": "3.7.24", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3b97c8492bcafbabe6b6fbd2ab35f2f04d932a8d", + "reference": "3b97c8492bcafbabe6b6fbd2ab35f2f04d932a8d", "shasum": "" }, "require": { @@ -324,7 +352,7 @@ "testing", "xunit" ], - "time": "2013-08-09 06:58:24" + "time": "2013-10-17 07:27:40" }, { "name": "phpunit/phpunit-mock-objects", @@ -377,17 +405,17 @@ }, { "name": "symfony/yaml", - "version": "v2.3.3", + "version": "v2.3.7", "target-dir": "Symfony/Component/Yaml", "source": { "type": "git", "url": "https://github.com/symfony/Yaml.git", - "reference": "v2.3.3" + "reference": "c1bda5b459d792cb253de12c65beba3040163b2b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.3.3", - "reference": "v2.3.3", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/c1bda5b459d792cb253de12c65beba3040163b2b", + "reference": "c1bda5b459d792cb253de12c65beba3040163b2b", "shasum": "" }, "require": { @@ -420,16 +448,16 @@ ], "description": "Symfony Yaml Component", "homepage": "http://symfony.com", - "time": "2013-07-21 12:12:18" + "time": "2013-10-17 11:48:01" } ], "aliases": [ ], "minimum-stability": "stable", - "stability-flags": [ - - ], + "stability-flags": { + "andy128k/pegp": 20 + }, "platform": [ ], diff --git a/src/dateformat.php b/src/dateformat.php new file mode 100644 index 0000000..3032fbf --- /dev/null +++ b/src/dateformat.php @@ -0,0 +1,186 @@ +value(self::DATE_DEFAULT), + Pegp::stri('us')->value(self::DATE_US), + Pegp::stri('european')->value(self::DATE_EUROPEAN), + Pegp::seq( + Pegp::optional( + Pegp::seq( + Pegp::oneOf( + Pegp::stri('big-endian')->value(self::DATE_BIG_ENDIAN), + Pegp::stri('little-endian')->value(self::DATE_LITTLE_ENDIAN), + Pegp::stri('middle-endian')->value(self::DATE_MIDDLE_ENDIAN)), + Pegp::re('\s+')->drop())->bitOr(), 0), + Pegp::oneOf( + Pegp::stri('slashes')->value(self::DATE_SLASHES), + Pegp::stri('dots')->value(self::DATE_DOTS), + Pegp::stri('hyphens')->value(self::DATE_HYPHENS), + Pegp::stri('spaces')->value(self::DATE_SPACES)))->bitOr()) + ->parseString($str); + } + + public static function datetimeFlagsFromString($str) + { + return + Pegp::oneOf( + Pegp::stri('default')->value(self::DATETIME_DEFAULT), + Pegp::stri('us')->value(self::DATETIME_US), + Pegp::stri('european')->value(self::DATETIME_EUROPEAN), + Pegp::seq( + Pegp::optional( + Pegp::seq( + Pegp::oneOf( + Pegp::stri('big-endian')->value(self::DATE_BIG_ENDIAN), + Pegp::stri('little-endian')->value(self::DATE_LITTLE_ENDIAN), + Pegp::stri('middle-endian')->value(self::DATE_MIDDLE_ENDIAN)), + Pegp::re('\s+')->drop())->bitOr(), 0), + Pegp::oneOf( + Pegp::stri('slashes')->value(self::DATE_SLASHES), + Pegp::stri('dots')->value(self::DATE_DOTS), + Pegp::stri('hyphens')->value(self::DATE_HYPHENS), + Pegp::stri('spaces')->value(self::DATE_SPACES)), + Pegp::re('\s+')->drop(), + Pegp::oneOf( + Pegp::stri('24')->value(self::TIME_24HOURS), + Pegp::stri('12-upper')->value(self::TIME_12HOURS_UPPER), + Pegp::stri('12-lower')->value(self::TIME_12HOURS_LOWER), + Pegp::stri('12')->value(self::TIME_12HOURS)), + Pegp::optional( + Pegp::seq( + Pegp::re('\s+')->drop(), + Pegp::stri('seconds'))->value(self::TIME_SECONDS), 0))->bitOr()) + ->parseString($str); + } + + /** + * Builds format string corresponding to given flags and controls. + * + * @param integer Format flags + * @param array Format values. + * Examples: + * array( + * 'Y', // year + * 'm', // month + * 'd', // day + * ) + * array( + * '%Y', // year + * '%m', // month + * '%d', // day + * '%H', '%l', '%p', '%P', // hour-24, hour-12, AM/PM, am/pm + * '%M', // minute + * '%S', // second + * ) + * @return string Format string + */ + public static function makeFormat($flags, $controls) + { + $date = self::makeDateFormat($flags, $controls); + $time = self::makeTimeFormat($flags, $controls); + if ($time) + return $date . ' ' . $time; + else + return $date; + } + + public static function makeDateFormat($flags, $controls) + { + $separator = self::$dateSeparators[$flags % 4]; + switch ($flags & 12) { + case self::DATE_BIG_ENDIAN: + return $controls[0].$separator.$controls[1].$separator.$controls[2]; + case self::DATE_LITTLE_ENDIAN: + return $controls[2].$separator.$controls[1].$separator.$controls[0]; + case self::DATE_MIDDLE_ENDIAN: + return $controls[1].$separator.$controls[2].$separator.$controls[0]; + default: + throw new Exception('Bad date format'); + } + } + + public static function makeTimeFormat($flags, $controls) + { + if (!($flags & 112)) // no time flags + return ''; + + $seconds = $flags & self::TIME_SECONDS; + switch ($flags & 48) { + case self::TIME_24HOURS: + $result = $controls[3].':'.$controls[7]; + if ($seconds) + $result .= ':'.$controls[8]; + break; + case self::TIME_12HOURS_UPPER: + $result = $controls[4].':'.$controls[7]; + if ($seconds) + $result .= ':'.$controls[8]; + $result .= ' '.$controls[5]; + break; + case self::TIME_12HOURS_LOWER: + $result = $controls[4].':'.$controls[7]; + if ($seconds) + $result .= ':'.$controls[8]; + $result .= ' '.$controls[6]; + break; + default: + throw new Exception('Bad time format'); + } + return $result; + } + + public static function parseDate($format, $str) + { + return strptime($str, self::makeFormat($format, self::$strftimeControls)); + } + + public static function formatDate($format, $timestamp) + { + return strftime(self::makeFormat($format, self::$strftimeControls), $timestamp); + } +} + +DateFormat::init(); + diff --git a/t/FormatTest.php b/t/FormatTest.php new file mode 100644 index 0000000..2f6245f --- /dev/null +++ b/t/FormatTest.php @@ -0,0 +1,36 @@ +assertEquals(DateFormat::DATE_DEFAULT, DateFormat::DATE_BIG_ENDIAN | DateFormat::DATE_HYPHENS); + $this->assertEquals(DateFormat::DATE_US, DateFormat::DATE_MIDDLE_ENDIAN | DateFormat::DATE_SLASHES); + $this->assertEquals(DateFormat::DATE_EUROPEAN, DateFormat::DATE_LITTLE_ENDIAN | DateFormat::DATE_DOTS); + } + + public function testDateFlagsFromString() + { + $this->assertEquals(DateFormat::DATE_DEFAULT, DateFormat::dateFlagsFromString('Default')); + $this->assertEquals(DateFormat::DATE_DEFAULT, DateFormat::dateFlagsFromString('Big-endian hyphEns')); + $this->assertEquals(DateFormat::DATE_EUROPEAN, DateFormat::dateFlagsFromString('European')); + $this->assertEquals(DateFormat::DATE_EUROPEAN, DateFormat::dateFlagsFromString('little-endian dots')); + $this->assertEquals(DateFormat::DATE_US, DateFormat::dateFlagsFromString('US')); + $this->assertEquals(DateFormat::DATE_US, DateFormat::dateFlagsFromString('Middle-Endian Slashes')); + $this->assertEquals(DateFormat::DATE_BIG_ENDIAN | DateFormat::DATE_SPACES, + DateFormat::dateFlagsFromString('big-endian spaces')); + } + + public function testDatetimeFlagsFromString() + { + $this->assertEquals(DateFormat::DATETIME_DEFAULT, DateFormat::datetimeFlagsFromString('Default')); + $this->assertEquals(DateFormat::DATETIME_DEFAULT, DateFormat::datetimeFlagsFromString('Big-endian hyphEns 24')); + $this->assertEquals(DateFormat::DATETIME_EUROPEAN, DateFormat::datetimeFlagsFromString('European')); + $this->assertEquals(DateFormat::DATETIME_EUROPEAN, DateFormat::datetimeFlagsFromString('little-endian dots 24')); + $this->assertEquals(DateFormat::DATETIME_US, DateFormat::datetimeFlagsFromString('US')); + $this->assertEquals(DateFormat::DATETIME_US, DateFormat::datetimeFlagsFromString('Middle-Endian Slashes 12-upper')); + $this->assertEquals(DateFormat::DATE_BIG_ENDIAN | DateFormat::DATE_SPACES | DateFormat::TIME_12HOURS_LOWER | DateFormat::TIME_SECONDS, + DateFormat::datetimeFlagsFromString("big-endian spaces \n 12-lower Seconds")); + } +} +