123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- 'use strict'
- var extend = require('xtend/mutable')
- module.exports = PostgresInterval
- function PostgresInterval (raw) {
- if (!(this instanceof PostgresInterval)) {
- return new PostgresInterval(raw)
- }
- extend(this, parse(raw))
- }
- var properties = ['seconds', 'minutes', 'hours', 'days', 'months', 'years']
- PostgresInterval.prototype.toPostgres = function () {
- var filtered = properties.filter(this.hasOwnProperty, this)
- // In addition to `properties`, we need to account for fractions of seconds.
- if (this.milliseconds && filtered.indexOf('seconds') < 0) {
- filtered.push('seconds')
- }
- if (filtered.length === 0) return '0'
- return filtered
- .map(function (property) {
- var value = this[property] || 0
- // Account for fractional part of seconds,
- // remove trailing zeroes.
- if (property === 'seconds' && this.milliseconds) {
- value = (value + this.milliseconds / 1000).toFixed(6).replace(/\.?0+$/, '')
- }
- return value + ' ' + property
- }, this)
- .join(' ')
- }
- var propertiesISOEquivalent = {
- years: 'Y',
- months: 'M',
- days: 'D',
- hours: 'H',
- minutes: 'M',
- seconds: 'S'
- }
- var dateProperties = ['years', 'months', 'days']
- var timeProperties = ['hours', 'minutes', 'seconds']
- // according to ISO 8601
- PostgresInterval.prototype.toISOString = PostgresInterval.prototype.toISO = function () {
- var datePart = dateProperties
- .map(buildProperty, this)
- .join('')
- var timePart = timeProperties
- .map(buildProperty, this)
- .join('')
- return 'P' + datePart + 'T' + timePart
- function buildProperty (property) {
- var value = this[property] || 0
- // Account for fractional part of seconds,
- // remove trailing zeroes.
- if (property === 'seconds' && this.milliseconds) {
- value = (value + this.milliseconds / 1000).toFixed(6).replace(/0+$/, '')
- }
- return value + propertiesISOEquivalent[property]
- }
- }
- var NUMBER = '([+-]?\\d+)'
- var YEAR = NUMBER + '\\s+years?'
- var MONTH = NUMBER + '\\s+mons?'
- var DAY = NUMBER + '\\s+days?'
- var TIME = '([+-])?([\\d]*):(\\d\\d):(\\d\\d)\\.?(\\d{1,6})?'
- var INTERVAL = new RegExp([YEAR, MONTH, DAY, TIME].map(function (regexString) {
- return '(' + regexString + ')?'
- })
- .join('\\s*'))
- // Positions of values in regex match
- var positions = {
- years: 2,
- months: 4,
- days: 6,
- hours: 9,
- minutes: 10,
- seconds: 11,
- milliseconds: 12
- }
- // We can use negative time
- var negatives = ['hours', 'minutes', 'seconds', 'milliseconds']
- function parseMilliseconds (fraction) {
- // add omitted zeroes
- var microseconds = fraction + '000000'.slice(fraction.length)
- return parseInt(microseconds, 10) / 1000
- }
- function parse (interval) {
- if (!interval) return {}
- var matches = INTERVAL.exec(interval)
- var isNegative = matches[8] === '-'
- return Object.keys(positions)
- .reduce(function (parsed, property) {
- var position = positions[property]
- var value = matches[position]
- // no empty string
- if (!value) return parsed
- // milliseconds are actually microseconds (up to 6 digits)
- // with omitted trailing zeroes.
- value = property === 'milliseconds'
- ? parseMilliseconds(value)
- : parseInt(value, 10)
- // no zeros
- if (!value) return parsed
- if (isNegative && ~negatives.indexOf(property)) {
- value *= -1
- }
- parsed[property] = value
- return parsed
- }, {})
- }
|