How to detect the browser's format for input[t

2019-04-08 15:02发布

问题:

Using Javascript, how would it be possible to detect the format of dates in date input fields (input[type=date])?

Tools like Modernizr only detect the capability of using an HTML5 datepicker (desirable especially for mobile devices, and their UI for selecting dates). However, I haven't been able to find any solution on detecting the format used by the browser.

I have an input field like this:

<input type="date" class="border-radius" min="2013-12-21" max="2015-12-20" data-persist-local="FromDate">

The value is entered with a jQuery call .val() if it's found in localStorage. I thought that since valid date formats for min and max attributes are in valid ISO format, getting the value of the field would return the same format. It turns out, it doesn't.

Testing on a Chrome browser (31.0.1650.63 m) with Swedish as primary language gives the ISO format, but using the same browser with Danish as primary language reverses the date format to dd-mm-yyyy instead of yyyy-mm-dd. I suspect it's the same for other locales.

I'm not looking to change the input format - and ideally there would be a function to get the date by a consistent "wire format" but I haven't found a way to get anything but the display format.

How do I detect the format of the input field, and consistently convert to a valid Date in JS, and back again?

回答1:

ideally there would be a function to get the date by a consistent "wire format"

There's a input.valueAsDate method which returns a Date object reflecting the input's current value.

According to experimentation (edit: with Chrome & Opera desktop versions on 2013-12-20), it appears that the displayed value of date inputs follows the same format as that returned by new Date().toLocaleDateString(), at least in Chrome.

There are then 3 representations of a date in action on the front-end:

  1. The Javascript date object
  2. The ISO date string for the input's attributes and ostensible value
  3. The date string represented to the user by the input.

To get any one of these from any of the other:

// From Javascript `Date` object to input value:
new Date().toISOString().substr( 0, 10 );

// From Javascript `Date` object to input display:
new Date().toLocaleDateString();

// From input value to Javascript `Date`:
input.valueAsDate;

// From input value to input display (step 3, then step 2):
input.valueAsDate.toLocaleDateString();

// From input display to Javascript `Date` object:
new Date( input.valueAsDate );

// From input display to input value (step 5, then step 1):
new Date( input.valueAsDate ).toISOString().substr( 0, 10 );

EDIT:

The above happens to work on Chrome. Desktop Safari 5.1.7 displays time in ISO format, meaning what you input is what the user sees. iOS Safari displays a dropdown with abbreviated month names in the format dd mmm yyyy. So it seems there is no standard.

Here's a little function that will give you the right conversions for desktop Chrome & Opera only:

var dateInput = ( function inputDateClosure(){
    // Type checking
    function getType( x ){
        return Object.prototype.toString.call( x );
    }

    function isDate( x ){
        return getType( x ) === '[object Date]';
    }

    function isInput( x ){
        return getType( x ) === '[object HTMLInputElement]' || '[object Object]' && Object.prototype.hasOwnProperty.call( x, 'value' );
    }

    function isString( x ){
        return getType( x ) === '[object String]';
    }

    function fromDateToValue( x ){
        return x.toISOString().substr( 0, 10 );
    }

    function fromDateToString( x ){
        return x.toLocaleDateString();
    }

    function fromInputToDate( x ){
        return x.valueAsDate;
    }

    function fromStringToDate( x ){
        return new Date( x.valueAsDate );
    }

    return function( x ){
        if( isDate( x ) ){
            return {
                asDate   :                   x,
                asValue  : fromDateToValue(  x ),
                asString : fromDateToString( x )
            }
        }
        else if( isString( x ) ){
            return {
                asDate   :                   fromStringToDate( x ),
                asValue  : fromDateToValue(  fromStringToDate( x ) ),
                asString : fromStringToDate( fromDateToString( x ) )
            }
        }
        else if( isInput( x ) ){
            return {
                asDate   :                   fromInputToDate( x ),
                asValue  : fromDateToValue(  fromInputToDate( x ) ),
                asString : fromDateToString( fromInputToDate( x ) )
            }
        }
    }
}() );