'use strict'; 
 | 
  
 | 
const Hoek = require('@hapi/hoek'); 
 | 
  
 | 
const Any = require('../any'); 
 | 
const Ref = require('../../ref'); 
 | 
  
 | 
  
 | 
const internals = {}; 
 | 
  
 | 
internals.isoDate = /^(?:[-+]\d{2})?(?:\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[12]\d|0[1-9]|3[01]))?|W(?:[0-4]\d|5[0-2])(?:-?[1-7])?|(?:00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[1-6])))(?![T]$|[T][\d]+Z$)(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24\:?00)(?:[.,]\d+(?!:))?)(?:\2[0-5]\d(?:[.,]\d+)?)?(?:[Z]|(?:[+-])(?:[01]\d|2[0-3])(?::?[0-5]\d)?)?)?)?$/; 
 | 
internals.invalidDate = new Date(''); 
 | 
internals.isIsoDate = (() => { 
 | 
  
 | 
    const isoString = internals.isoDate.toString(); 
 | 
  
 | 
    return (date) => { 
 | 
  
 | 
        return date && (date.toString() === isoString); 
 | 
    }; 
 | 
})(); 
 | 
  
 | 
internals.Date = class extends Any { 
 | 
  
 | 
    constructor() { 
 | 
  
 | 
        super(); 
 | 
        this._type = 'date'; 
 | 
    } 
 | 
  
 | 
    _base(value, state, options) { 
 | 
  
 | 
        const result = { 
 | 
            value: (options.convert && internals.Date.toDate(value, this._flags.format, this._flags.timestamp, this._flags.multiplier)) || value 
 | 
        }; 
 | 
  
 | 
        if (result.value instanceof Date && !isNaN(result.value.getTime())) { 
 | 
            result.errors = null; 
 | 
        } 
 | 
        else if (!options.convert) { 
 | 
            result.errors = this.createError('date.strict', { value }, state, options); 
 | 
        } 
 | 
        else { 
 | 
            let type; 
 | 
            if (internals.isIsoDate(this._flags.format)) { 
 | 
                type = 'isoDate'; 
 | 
            } 
 | 
            else if (this._flags.timestamp) { 
 | 
                type = `timestamp.${this._flags.timestamp}`; 
 | 
            } 
 | 
            else { 
 | 
                type = 'base'; 
 | 
            } 
 | 
  
 | 
            result.errors = this.createError(`date.${type}`, { value }, state, options); 
 | 
        } 
 | 
  
 | 
        return result; 
 | 
    } 
 | 
  
 | 
    static toDate(value, format, timestamp, multiplier) { 
 | 
  
 | 
        if (value instanceof Date) { 
 | 
            return value; 
 | 
        } 
 | 
  
 | 
        if (typeof value === 'string' || 
 | 
            (typeof value === 'number' && !isNaN(value) && isFinite(value))) { 
 | 
  
 | 
            const isIsoDate = format && internals.isIsoDate(format); 
 | 
            if (!isIsoDate && 
 | 
                typeof value === 'string' && 
 | 
                /^[+-]?\d+(\.\d+)?$/.test(value)) { 
 | 
  
 | 
                value = parseFloat(value); 
 | 
            } 
 | 
  
 | 
            let date; 
 | 
            if (isIsoDate) { 
 | 
                date = format.test(value) ? new Date(value.toString()) : internals.invalidDate; 
 | 
            } 
 | 
            else if (timestamp) { 
 | 
                date = /^\s*$/.test(value) ? internals.invalidDate : new Date(value * multiplier); 
 | 
            } 
 | 
            else { 
 | 
                date = new Date(value); 
 | 
            } 
 | 
  
 | 
            if (!isNaN(date.getTime())) { 
 | 
                return date; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        return null; 
 | 
    } 
 | 
  
 | 
    iso() { 
 | 
  
 | 
        if (this._flags.format === internals.isoDate) { 
 | 
            return this; 
 | 
        } 
 | 
  
 | 
        const obj = this.clone(); 
 | 
        obj._flags.format = internals.isoDate; 
 | 
        return obj; 
 | 
    } 
 | 
  
 | 
    timestamp(type = 'javascript') { 
 | 
  
 | 
        const allowed = ['javascript', 'unix']; 
 | 
        Hoek.assert(allowed.includes(type), '"type" must be one of "' + allowed.join('", "') + '"'); 
 | 
  
 | 
        if (this._flags.timestamp === type) { 
 | 
            return this; 
 | 
        } 
 | 
  
 | 
        const obj = this.clone(); 
 | 
        obj._flags.timestamp = type; 
 | 
        obj._flags.multiplier = type === 'unix' ? 1000 : 1; 
 | 
        return obj; 
 | 
    } 
 | 
  
 | 
    _isIsoDate(value) { 
 | 
  
 | 
        return internals.isoDate.test(value); 
 | 
    } 
 | 
  
 | 
}; 
 | 
  
 | 
internals.compare = function (type, compare) { 
 | 
  
 | 
    return function (date) { 
 | 
  
 | 
        const isNow = date === 'now'; 
 | 
        const isRef = Ref.isRef(date); 
 | 
  
 | 
        if (!isNow && !isRef) { 
 | 
            date = internals.Date.toDate(date); 
 | 
        } 
 | 
  
 | 
        Hoek.assert(date, 'Invalid date format'); 
 | 
  
 | 
        return this._test(type, date, function (value, state, options) { 
 | 
  
 | 
            let compareTo; 
 | 
            if (isNow) { 
 | 
                compareTo = Date.now(); 
 | 
            } 
 | 
            else if (isRef) { 
 | 
                const refValue = date(state.reference || state.parent, options); 
 | 
                compareTo = internals.Date.toDate(refValue); 
 | 
  
 | 
                if (!compareTo) { 
 | 
                    return this.createError('date.ref', { ref: date, value: refValue }, state, options); 
 | 
                } 
 | 
  
 | 
                compareTo = compareTo.getTime(); 
 | 
            } 
 | 
            else { 
 | 
                compareTo = date.getTime(); 
 | 
            } 
 | 
  
 | 
            if (compare(value.getTime(), compareTo)) { 
 | 
                return value; 
 | 
            } 
 | 
  
 | 
            return this.createError('date.' + type, { limit: new Date(compareTo), value }, state, options); 
 | 
        }); 
 | 
    }; 
 | 
}; 
 | 
  
 | 
  
 | 
internals.Date.prototype.min = internals.compare('min', (value, date) => value >= date); 
 | 
internals.Date.prototype.max = internals.compare('max', (value, date) => value <= date); 
 | 
internals.Date.prototype.greater = internals.compare('greater', (value, date) => value > date); 
 | 
internals.Date.prototype.less = internals.compare('less', (value, date) => value < date); 
 | 
  
 | 
  
 | 
module.exports = new internals.Date(); 
 |