admin管理员组

文章数量:1323150

I need a function to transform decimal values of years in years, months and days. Ex: 1.5 years = 1 year, 6 month. 2.2527397260273973 years = 2 years, 3 months and 1 day.

I started with this function:

function yearsToYearsMonthsDays(value){
var years = Math.floor(value);
var months =  Math.floor( (value - years) /(1/12) );
var days = Math.floor ( ( (value - years) /(1/12) - Math.floor((value - years) /(1/12)) ) / (1/365) );
var result = years + " years, " + months + " months, " + days + " days";
    Logger.log(result);
}

But sometimes it doesn't work (ex: 0.75 doesn't produces 9 months).

Any help?

I need a function to transform decimal values of years in years, months and days. Ex: 1.5 years = 1 year, 6 month. 2.2527397260273973 years = 2 years, 3 months and 1 day.

I started with this function:

function yearsToYearsMonthsDays(value){
var years = Math.floor(value);
var months =  Math.floor( (value - years) /(1/12) );
var days = Math.floor ( ( (value - years) /(1/12) - Math.floor((value - years) /(1/12)) ) / (1/365) );
var result = years + " years, " + months + " months, " + days + " days";
    Logger.log(result);
}

But sometimes it doesn't work (ex: 0.75 doesn't produces 9 months).

Any help?

Share asked Feb 27, 2014 at 3:48 craftApprenticecraftApprentice 2,77720 gold badges61 silver badges87 bronze badges 3
  • Works fine as far as I can tell. jsfiddle/HaJW4 – Mark Parnell Commented Feb 27, 2014 at 4:03
  • Decimal years may convert to a date, but it doesn't accurately convert to a period of months and days since months are not of equal lengths and one month changes length from year to year. – RobG Commented Feb 27, 2014 at 5:00
  • I've solved something similar here: stackoverflow./questions/29400171/…. It deals with a situation where you're dealing in actual years (i.e. 2015.252739 or 'April 3 2015') but has leap year analysis which means it's not exactly right for time spans (i.e. 2.252739 or '2 years 3 months and 1 day') – Alien Life Form Commented Apr 1, 2015 at 20:38
Add a ment  | 

4 Answers 4

Reset to default 6

I think the best way would be to change all to days, for example:

function yearsToYearsMonthsDays(value)
{
    var totalDays = value * 365;
    var years = Math.floor(totalDays/365);
    var months = Math.floor((totalDays-(years *365))/30);
    var days = Math.floor(totalDays - (years*365) - (months * 30));
    var result = years + " years, " + months + " months, " + days + " days";
    Logger.log(result);
}

My contribution converts decimal years into time units ranging from eons (billion years) to nanoseconds (billionths of a second), and is output formatted with mas in a slightly chatty style.

There are many ways to convert time, and the presumptions have to be understood. Here are mine:

This converts based on 1) an average month having 30.436875 days, per the Gregorian calendar; 2) a month having 730.485 hours average for a 4-year period which includes 1 leap year; and 3) there being 8765.82 hours per year (not 8760). These internal constants won't fit every application, of course, but should be good enough for general use. For example, my function adds about a minute of time to the OP's example of:

2.2527397260273973 years = 2 years, 3 months and 1 day

where

getTimeFromYears( 2.2527397260273973 );

outputs "2 years, 3 months, 1 day and 57 seconds".

Some units seemed unnecessary, such as weeks when you have days and months, and decades when you have years and centuries, but those can easily be added into the logic. Run the snippet to see the examples.

function getTimeFromYears( _years ) {
// to omit a unit from the output, multiply its value by zero; see gyears

    "use strict";

    var _hoursInEon            = 8765820000000     // eon =         1,000,000,000 years (billion)
        , _hoursInGalacticYear = 2016138600000     // galactic year = 230,000,000 years (230 million)
        , _hoursInEpoch        =    8765820000     // epoch =           1,000,000 years (million)
        , _hoursInMillenium    =       8765820     // millenium =           1,000 years
        , _hoursInCentury      =        876582   
        , _hoursInYear         =          8765.82  // often cited as 8760, or 730 * 12  // 365.2425 days in year
        , _hoursInMonth        =           730.485 // hours average per month for a 4-year period which includes 1 leap year
                                                   // average month has 30.436875 days, Gregorian calendar
        , _hoursInDay          =            24
        , _hoursInHour         =             1
        , _hoursInMinute       =             0.0166666666666667
        , _hoursInSecond       =             0.000277778
        , _hoursInMillisecond  =             0.000000277778       // A millisecond is one-thousandth of a second
        , _hoursInNanosecond   =             0.000000000000277778 // A nanosecond is one-billionth of a second


        , totalHours = _years * _hoursInYear
        
        , eons   = Math.floor(   totalHours
                    / _hoursInEon )

        , gyears = Math.floor( ( totalHours - ( eons * _hoursInEon ) )
                    / _hoursInGalacticYear ) * 0

        , epochs = Math.floor( ( totalHours - ( eons * _hoursInEon ) - ( gyears * _hoursInGalacticYear ) )
                    / _hoursInEpoch )

        , mills  = Math.floor( ( totalHours - ( eons * _hoursInEon ) - ( gyears * _hoursInGalacticYear ) - ( epochs * _hoursInEpoch ) )
                    / _hoursInMillenium )

        , cents  = Math.floor( ( totalHours - ( eons * _hoursInEon ) - ( gyears * _hoursInGalacticYear ) - ( epochs * _hoursInEpoch ) - ( mills * _hoursInMillenium ) )
                    / _hoursInCentury )

        , years  = Math.floor( ( totalHours - ( eons * _hoursInEon ) - ( gyears * _hoursInGalacticYear ) - ( epochs * _hoursInEpoch ) - ( mills * _hoursInMillenium ) - ( cents * _hoursInCentury ) )
                    / _hoursInYear )
    
        , months = Math.floor( ( totalHours - ( eons * _hoursInEon ) - ( gyears * _hoursInGalacticYear ) - ( epochs * _hoursInEpoch ) - ( mills * _hoursInMillenium ) - ( cents * _hoursInCentury ) - ( years * _hoursInYear ) )
                    / _hoursInMonth )
    
        , days   = Math.floor( ( totalHours - ( eons * _hoursInEon ) - ( gyears * _hoursInGalacticYear ) - ( epochs * _hoursInEpoch ) - ( mills * _hoursInMillenium ) - ( cents * _hoursInCentury ) - ( years * _hoursInYear ) - ( months * _hoursInMonth ) )
                    / _hoursInDay )
    
        , hours  = Math.floor( ( totalHours - ( eons * _hoursInEon ) - ( gyears * _hoursInGalacticYear ) - ( epochs * _hoursInEpoch ) - ( mills * _hoursInMillenium ) - ( cents * _hoursInCentury ) - ( years * _hoursInYear ) - ( months * _hoursInMonth ) - ( days * _hoursInDay ) )
                    / _hoursInHour )
    
        , mins  = Math.floor( ( totalHours - ( eons * _hoursInEon ) - ( gyears * _hoursInGalacticYear ) - ( epochs * _hoursInEpoch ) - ( mills * _hoursInMillenium ) - ( cents * _hoursInCentury ) - ( years * _hoursInYear ) - ( months * _hoursInMonth ) - ( days * _hoursInDay ) - ( hours * _hoursInHour ) )
                    / _hoursInMinute ) 

        , secs  = Math.floor( ( totalHours - ( eons * _hoursInEon ) - ( gyears * _hoursInGalacticYear ) - ( epochs * _hoursInEpoch ) - ( mills * _hoursInMillenium ) - ( cents * _hoursInCentury ) - ( years * _hoursInYear ) - ( months * _hoursInMonth ) - ( days * _hoursInDay ) - ( hours * _hoursInHour ) - ( mins * _hoursInMinute ) )
                    / _hoursInSecond )

        , msecs = Math.floor( ( totalHours - ( eons * _hoursInEon ) - ( gyears * _hoursInGalacticYear ) - ( epochs * _hoursInEpoch ) - ( mills * _hoursInMillenium ) - ( cents * _hoursInCentury ) - ( years * _hoursInYear ) - ( months * _hoursInMonth ) - ( days * _hoursInDay ) - ( hours * _hoursInHour ) - ( mins * _hoursInMinute ) - ( secs * _hoursInSecond ) )
                    / _hoursInMillisecond )

        , nsecs = Math.floor( ( totalHours - ( eons * _hoursInEon ) - ( gyears * _hoursInGalacticYear ) - ( epochs * _hoursInEpoch ) - ( mills * _hoursInMillenium ) - ( cents * _hoursInCentury ) - ( years * _hoursInYear ) - ( months * _hoursInMonth ) - ( days * _hoursInDay ) - ( hours * _hoursInHour ) - ( mins * _hoursInMinute ) - ( secs * _hoursInSecond ) - ( msecs * _hoursInMillisecond ) )
                    / _hoursInNanosecond )


        , _eonsPhrase   = ( eons   < 1 ? '' : eons   === 1 ? '1 eon'           : addCommas( eons   ) + ' eons'           )
        , _gyearsPhrase = ( gyears < 1 ? '' : gyears === 1 ? '1 galactic year' : addCommas( gyears ) + ' galactic years' )
        , _epochsPhrase = ( epochs < 1 ? '' : epochs === 1 ? '1 epoch'         : addCommas( epochs ) + ' epochs'         )
        , _millsPhrase  = ( mills  < 1 ? '' : mills  === 1 ? '1 millenium'     : mills  + ' millenia'  )
        , _centsPhrase  = ( cents  < 1 ? '' : cents  === 1 ? '1 century'       : cents  + ' centuries' )
        , _yearsPhrase  = ( years  < 1 ? '' : years  === 1 ? '1 year'          : years  + ' years'     )
        , _monthsPhrase = ( months < 1 ? '' : months === 1 ? '1 month'         : months + ' months'    )
        , _daysPhrase   = ( days   < 1 ? '' : days   === 1 ? '1 day'           : days   + ' days'      )
        , _hoursPhrase  = ( hours  < 1 ? '' : hours  === 1 ? '1 hour'          : hours  + ' hours'     )
        , _minsPhrase   = ( mins   < 1 ? '' : mins   === 1 ? '1 minute'        : mins   + ' minutes'   )
        , _secsPhrase   = ( secs   < 1 ? '' : secs   === 1 ? '1 second'        : secs   + ' seconds'   )
        , _msecsPhrase  = ( msecs  < 1 ? '' : msecs  === 1 ? '1 millisecond'   : addCommas( msecs ) + ' milliseconds' )
        , _nsecsPhrase  = ( nsecs  < 1 ? '' : nsecs  === 1 ? '1 nanosecond'    : addCommas( nsecs ) + ' nanoseconds'  )

        , _phrasePart = new Array(13)
        , _phrasesInUse = 0
        , _phrasesUsed  = 0
        , _joiner = ','
        , _result = ''
    ;


    ////////////////////////////////////////////////////
    // cosmetic adjustments
    if( eons > 999999 ) { _joiner = ';'; }
    if( secs > 0 || mins > 0 ) { _msecsPhrase = _nsecsPhrase = ''; } 
    ////////////////////////////////////////////////////

    _phrasePart[  0 ] = _eonsPhrase;
    _phrasePart[  1 ] = _gyearsPhrase;
    _phrasePart[  2 ] = _epochsPhrase;
    _phrasePart[  3 ] = _millsPhrase;
    _phrasePart[  4 ] = _centsPhrase;
    _phrasePart[  5 ] = _yearsPhrase;
    _phrasePart[  6 ] = _monthsPhrase;
    _phrasePart[  7 ] = _daysPhrase;
    _phrasePart[  8 ] = _hoursPhrase;
    _phrasePart[  9 ] = _minsPhrase;
    _phrasePart[ 10 ] = _secsPhrase;
    _phrasePart[ 11 ] = _msecsPhrase;
    _phrasePart[ 12 ] = _nsecsPhrase;

    // count the phrase pieces to use
    for( var i = 0; i < _phrasePart.length; i++ ) {
        if( _phrasePart[ i ].length ) { _phrasesInUse++; }
    }

    // assemble the output
    for( var i = 0; i < _phrasePart.length; i++ ) {
        if( _phrasePart[ i ].length ) {
            _result += _phrasePart[ i ];
            _phrasesUsed++;

            // only for the last phrase
            if( _phrasesInUse - _phrasesUsed === 1 ) {
                _result += ' and ';
            
            } else
            if( _phrasesInUse - _phrasesUsed > 0 ) {
                _result += ( _joiner + ' ' );
            }
        }
    }

    return _result;
};


function addCommas(t) {
    t += ""; var x = t.split("."), x1 = x[0], x2 = x.length > 1 ? "." + x[1] : "";
    for (var r = /(\d+)(\d{3})/; r.test(x1); ) x1 = x1.replace(r, "$1,$2");
    return x1 + x2;
};


console.log( 'getTimeFromYears( .75 ) -> ' + getTimeFromYears( .75 ) ); // 9 months
console.log( 'getTimeFromYears( 9/12 ) -> ' + getTimeFromYears( 9/12 ) ); // 9 months
console.log( 'getTimeFromYears( 1/365.2425 ) -> ' + getTimeFromYears( 1/365.2425 ) ); // 1 day
console.log( 'getTimeFromYears( 1/365.2425 * 14 ) -> ' + getTimeFromYears( 1/365.2425 * 14 ) ); // 14 days
console.log( 'getTimeFromYears( 1/365.2425 / 24 ) -> ' + getTimeFromYears( 1/365.2425 / 24 ) ); // 1 hour
console.log( 'getTimeFromYears( 1/365.2425 / 24 * 730.485 ) -> ' + getTimeFromYears( 1/365.2425 / 24 * 730.485 ) ); // 1 month
console.log( 'getTimeFromYears( 1/365.2425 * 0.0000000000000115741 ) -> ' + getTimeFromYears( 1/365.2425 * 0.0000000000000115741 ) ); // 1 nanosecond
console.log( 'getTimeFromYears( 1/365.2425 / 24 * 0.000000000000277778 ) -> ' + getTimeFromYears( 1/365.2425 / 24 * 0.000000000000277778 ) ); // 1 nanosecond
console.log( 'getTimeFromYears( 1/365.2425 / 24 * 0.000000000000277778 * 12000 ) -> ' + getTimeFromYears( 1/365.2425 / 24 * 0.000000000000277778 * 12000 ) ); // 12,000 nanoseconds
console.log( 'getTimeFromYears( 1/365.2425 / 24 * 0.000000000000277778 * 1000000 ) -> ' + getTimeFromYears( 1/365.2425 / 24 * 0.000000000000277778 * 1000000 ) ); // 1 millisecond
console.log( 'getTimeFromYears( 1/365.2425 / 24 * 0.000000000000277778 * 12345678 ) -> ' + getTimeFromYears( 1/365.2425 / 24 * 0.000000000000277778 * 12345678 ) ); // 12 milliseconds and 345,678 nanoseconds
console.log( 'getTimeFromYears( 123456789 ) -> ' + getTimeFromYears( 123456789 ) ); // 123 epochs, 456 millenia, 7 centuries, 88 years, 11 months, 30 days, 10 hours, 29 minutes and 5 seconds
console.log( 'getTimeFromYears( 9876543210 ) -> ' + getTimeFromYears( 9876543210 ) ); // 9 eons, 876 epochs, 543 millenia, 2 centuries, 10 years and 11 seconds
console.log( 'getTimeFromYears( 2.2527397260273973 ) -> ' + getTimeFromYears( 2.2527397260273973 ) ); // 2 years, 3 months, 1 day and 57 seconds

Your script works well here (tested in firebug console).

A call to your function with 0.75 as a parameter produces :

0 years, 9 months, 0 days

What do you exactly want it to do?

If you want it to remove the "0" values, then you need to test them and don't append them into the string if they are equals to 0, eg :

var result = "";
if(years !=0){result += year + " years"}

I stated using jorgeregidor's answer and I generalized it a bit.

function years_to_ymdh(value) {
    console.log('initialy : '+ value + ' years');

    var results=[], rest=value;
    var units=['years', 'months', 'days', 'hours', 'minutes'];
    var converters=[1, 12, 365.25, 365.25*24, 365.25*24*60];

    units.forEach(function(d,i){
        if (i==0) results[i] = Math.floor(rest);
        else results[i] = Math.floor(rest * converters[i]);
        if (results[i] != 0) rest = rest % (results[i]/converters[i]);
        console.log('-'+results[i]+' '+d+' -> rest', rest);
    });

    var text = results.map( (d,i) => d+' '+units[i] ).join(', ');
    console.log(text);

    // return text;
    return results;
}

years_to_ymdh(2.2527397260273973)
-2 years -> rest 0.25273972602739736
-3 months -> rest 0.00273972602739736
-1 days -> rest 0.000001875240265258784
-0 hours -> rest 0.000001875240265258784
-0 minutes -> rest 0.000001875240265258784
2 years, 3 months, 1 days, 0 hours, 0 minutes

To get seconds it's pretty easy to add 'seconds' to the units array and 365.25*24*60*60 to the converters array.

本文标签: Javascript function to convert decimal years value into yearsmonths and daysStack Overflow