Last active
August 29, 2015 14:18
-
-
Save zemd/d086e86f20ed74c1782e to your computer and use it in GitHub Desktop.
Fixing storing dates' milliseconds in mongodb with DoctrineODM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace Opesho\CommonBundle\Doctrine\ODM\MongoDB\Types; | |
| use Doctrine\ODM\MongoDB\Types\Type; | |
| use Opesho\CommonBundle\Utils\DateUtils; | |
| class DateType extends Type | |
| { | |
| public function convertToDatabaseValue($value) | |
| { | |
| if ($value === null) { | |
| return null; | |
| } | |
| if ($value instanceof \MongoDate) { | |
| return $value; | |
| } | |
| if ($value instanceof \DateTime) { | |
| return new \MongoDate(intval($value->format("U")), intval($value->format("u"))); | |
| } elseif (is_numeric($value)) { | |
| list($sec, $usec) = DateUtils::getSecUsec($value); | |
| return new \MongoDate($sec, $usec); | |
| } elseif (is_string($value)) { | |
| $datetime = new \DateTime($value, new \DateTimeZone("UTC")); | |
| if ($datetime === false) { | |
| throw new \InvalidArgumentException(sprintf("Could not convert %s to a date value", is_scalar($value) ? '"' . $value . '"' : gettype($value))); | |
| } | |
| return new \MongoDate(intval($datetime->format("U")), intval($datetime->format("u"))); | |
| } | |
| } | |
| public function convertToPHPValue($value) | |
| { | |
| if ($value === null) { | |
| return null; | |
| } | |
| if ($value instanceof \MongoDate) { | |
| return new \DateTime(date("Y-m-d H:i:s.", $value->sec) . $value->usec, new \DateTimeZone("UTC")); | |
| } elseif (is_numeric($value)) { | |
| list($sec, $usec) = DateUtils::getSecUsec($value); | |
| return new \DateTime(date("Y-m-d H:i:s.", $sec) . $usec, new \DateTimeZone("UTC")); | |
| } elseif ($value instanceof \DateTime) { | |
| return $value; | |
| } | |
| return new \DateTime($value, new \DateTimeZone("UTC")); | |
| } | |
| public function closureToMongo() | |
| { | |
| return 'if ($value instanceof \MongoDate) { | |
| $return = $value; | |
| } else if ($value instanceof \DateTime) { | |
| $return = new \MongoDate(intval($value->format("U")), intval($value->format("u"))); | |
| } elseif (is_numeric($value)) { | |
| list($sec, $usec) = \Opesho\CommonBundle\Utils\DateUtils::getSecUsec($value); | |
| $return = new \MongoDate($sec, $usec); | |
| } elseif (is_string($value)) { | |
| $datetime = new \DateTime($value, new \DateTimeZone("UTC")); | |
| $return = new \MongoDate(intval($datetime->format("U")), intval($datetime->format("u"))); | |
| }'; | |
| } | |
| public function closureToPHP() | |
| { | |
| return 'if ($value instanceof \MongoDate) { | |
| $return = new \DateTime(date("Y-m-d H:i:s.", $value->sec) . $value->usec, new \DateTimeZone("UTC")); | |
| } elseif (is_numeric($value)) { | |
| list($sec, $usec) = \Opesho\CommonBundle\Utils\DateUtils::getSecUsec($value); | |
| $return = new \DateTime(date("Y-m-d H:i:s.", $sec) . $usec, new \DateTimeZone("UTC")); | |
| } elseif ($value instanceof \DateTime) { | |
| $return = $value; | |
| } else { | |
| $return = new \DateTime($value, new \DateTimeZone("UTC")); | |
| }'; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace Opesho\CommonBundle\Utils; | |
| use DateTime; | |
| /** | |
| * Utils for datetime manipulating | |
| */ | |
| final class DateUtils | |
| { | |
| /** | |
| * Helper for creating microseconds aware \DateTime objects. Useful for storing dates in mongo | |
| * | |
| * @param string $value | |
| * @return DateTime | |
| */ | |
| public static function getDate($value = "now") | |
| { | |
| $micro = explode(" ", microtime()); | |
| $micros = substr($micro[0], 1, 7); | |
| return new DateTime(date('Y-m-d H:i:s', strtotime($value)) . $micros, new \DateTimeZone("UTC")); | |
| } | |
| /** | |
| * Returns array with two values of seconds and milliseconds or microseconds | |
| * | |
| * @param int $value | |
| * @return array | |
| */ | |
| public static function getSecUsec($value) | |
| { | |
| $value = intval($value); | |
| $sec = $value; | |
| $usec = 0; | |
| if ($value >= 100000000000000) { | |
| // supposed the value is microseconds | |
| $sec = intval($value / 1000000); | |
| $usec = $value % 1000000; | |
| } else if ($value >= 100000000000) { | |
| // supposed the value is milliseconds | |
| $sec = intval($value / 1000); | |
| $usec = $value % 1000; | |
| } | |
| // else the value is seconds | |
| return [$sec, $usec]; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace Opesho\CommonBundle; | |
| use Doctrine\ODM\MongoDB\Types\Type; | |
| use Symfony\Component\HttpKernel\Bundle\Bundle; | |
| use Symfony\Component\DependencyInjection\ContainerBuilder; | |
| class OpeshoCommonBundle extends Bundle | |
| { | |
| public function __construct() { | |
| Type::overrideType(Type::DATE, '\Opesho\CommonBundle\Doctrine\ODM\MongoDB\Types\DateType'); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment