What is the exact Excel Days360 algorithm? - c#

I'm porting some calculations from Excel to C# which use the Days360 function (the default/US method). Using the Wikipedia page as a guide, I came up with this code:
public static int Days360(DateTime a, DateTime b)
{
var dayA = a.Day;
var dayB = b.Day;
if (IsLastDayOfFebruary(a) && IsLastDayOfFebruary(b))
dayB = 30;
if (dayA == 31 || IsLastDayOfFebruary(a))
dayA = 30;
if (dayA == 30 && dayB == 31)
dayB = 30;
return ((b.Year - a.Year) * 12 + b.Month - a.Month) * 30 + dayB - dayA;
}
private static bool IsLastDayOfFebruary(DateTime date)
{
if (date.Month != 2)
return false;
int lastDay = DateTime.DaysInMonth(date.Year, 2);
return date.Day == lastDay;
}
I tested it with a (small) range of inputs and the results mostly agree with Excel's native function except if I use 2015-02-28 for both a and b. My code returns 0 and Excel -2.
My result seems more reasonable but at this point, I'd prefer to calculate the exact same result as Excel. There might be other inputs where they disagree so I don't want to make a special case just for that date.
Does anyone know the exact algorithm that Excel uses?
EDIT: There was a glaring bug in the original code I posted which is unrelated to the question. I had already fixed that one but I copied from the wrong file when posting the question.

According to this Wikipedia article the Microsoft Excel Days360 function is equivalent to 30/360 BMA/PSA. So to get exact results as MS Excel we need to implement the BMA/PSA method. I have implemented the method.
private double Days360(DateTime StartDate, DateTime EndDate)
{
int StartDay = StartDate.Day;
int StartMonth = StartDate.Month;
int StartYear = StartDate.Year;
int EndDay = EndDate.Day;
int EndMonth = EndDate.Month;
int EndYear = EndDate.Year;
if (StartDay == 31 || IsLastDayOfFebruary(StartDate))
{
StartDay = 30;
}
if (StartDay == 30 && EndDay == 31)
{
EndDay = 30;
}
return ((EndYear - StartYear) * 360) + ((EndMonth - StartMonth) * 30) + (EndDay - StartDay);
}
private bool IsLastDayOfFebruary(DateTime date)
{
return date.Month == 2 && date.Day == DateTime.DaysInMonth(date.Year, date.Month);
}

I had the same need, I found the solution in the function on line 51 of this phpexcel library
dateDiff360
this is part of the class code for the calculation
/**
* Identify if a year is a leap year or not
*
* #param integer $year The year to test
* #return boolean TRUE if the year is a leap year, otherwise FALSE
*/
public static function isLeapYear($year)
{
return ((($year % 4) == 0) && (($year % 100) != 0) || (($year % 400) == 0));
}
/**
* Return the number of days between two dates based on a 360 day calendar
*
* #param integer $startDay Day of month of the start date
* #param integer $startMonth Month of the start date
* #param integer $startYear Year of the start date
* #param integer $endDay Day of month of the start date
* #param integer $endMonth Month of the start date
* #param integer $endYear Year of the start date
* #param boolean $methodUS Whether to use the US method or the European method of calculation
* #return integer Number of days between the start date and the end date
*/
private static function dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, $methodUS)
{
if ($startDay == 31) {
--$startDay;
} elseif ($methodUS && ($startMonth == 2 && ($startDay == 29 || ($startDay == 28 && !self::isLeapYear($startYear))))) {
$startDay = 30;
}
if ($endDay == 31) {
if ($methodUS && $startDay != 30) {
$endDay = 1;
if ($endMonth == 12) {
++$endYear;
$endMonth = 1;
} else {
++$endMonth;
}
} else {
$endDay = 30;
}
}
return $endDay + $endMonth * 30 + $endYear * 360 - $startDay - $startMonth * 30 - $startYear * 360;
}

This algorithm also include the optional parameter method:
int startMonthDays = 0;
int endMonthDays = 0;
double diff = 0;
if(method.Equals("TRUE"))
{
if(dtStartDate.getDay() < 30)
{
startMonthDays = (30 - dtStartDate.getDay());
}
else
{
startMonthDays = 0;
}
if(dtEndDate.getDay() < 30)
{
endMonthDays = dtEndDate.getDay();
}
else
{
endMonthDays = 30;
}
diff = (dtEndDate.getYear() - dtStartDate.getYear())*360 +
(dtEndDate.getMonth() - dtStartDate.getMonth() - 1)*30 +
startMonthDays + endMonthDays;
}
else
{
if(DateCalendar.daysInMonth(dtStartDate.getYear(), dtStartDate.getMonth()) == dtStartDate.getDay())
{
startMonthDays = 0;
}
else
{
startMonthDays = (30 - dtStartDate.getDay());
}
if(DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth()) == dtEndDate.getDay())
{
if(dtStartDate.getDay() < DateCalendar.daysInMonth(dtStartDate.getYear(), dtStartDate.getMonth()) - 1)
{
if(DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth()) > 30)
{
endMonthDays = DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth());
}
else
{
endMonthDays = dtEndDate.getDay();
}
}
else
{
if(DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth()) > 30)
{
endMonthDays = DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth()) - 1;
}
else
{
endMonthDays = dtEndDate.getDay();
}
}
}
else
{
endMonthDays = dtEndDate.getDay();
}
diff = (dtEndDate.getYear() - dtStartDate.getYear())*360 +
(dtEndDate.getMonth() - dtStartDate.getMonth() - 1)*30 +
startMonthDays + endMonthDays;
}
with
public static int daysInMonth (int year, int month)
{
if (DateTime.IsLeapYear(year) && month == 2)
{
return 29;
}
else
{
return table[month - 1];
}
}
and
private static readonly int[] table = new int[]{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

Test the next
public static int Days360(DateTime a, DateTime b)
{
var dayA = a.Day;
var dayB = b.Day;
if (IsLastDayOfMonth(a) && IsLastDayOfMonth(b)) {
dayB = Math.min(30, dayB);
} else if (dayA == 30 && dayB ==31) {
DayB = 30;
}
if (IsLastDayOfMonth(a))
dayA = 30;
return ((b.Year - a.Year) * 360 + b.Month - a.Month) * 30 + dayB - dayA;
}
private static bool IsLastDayOfMonth(DateTime date)
{
int lastDay = DateTime.DaysInMonth(date.Year, date.Month);
return date.Day == lastDay;
}

Related

Validating phone numbers with specific character size in C#

There is a method in my program that verifies if a phone number has 13 characters, I want to return false if there is more or less characters than 13, and return true if has 13 characters.
So far, i made this, i think i got the 13 characters, anything less or more it gives me an ArgumentOutOfRangeException:
public bool CheckPhone()
{
int sum = 0;
int rest;
int i;
for (i = 1; i <= 12; i++)
{
if (Phone.Substring(i - 1, i - (i - 1)).Contains("")==false)
{
return false;
}
else
{
sum += int.Parse(Phone.Substring(i - 1, i - (i - 1))) * (13 - i);
}
}
rest = (sum * 11) % 12;
if ((rest == 11) || (rest == 12))
{
rest = 0;
return true;
}
else
{
return false;
}
}
public bool CheckPhone()
=> Phone.Length == 13 && Phone.All(Char.IsDigit);

Exponential progress reporting

I would like to report to an user the current progress about a background counter, however, I'm stuck in my method.
Indeed, I want more the counter timeout is higher and more there will be information.
For example, if the user sets a counter with a timeout of 60 secs, the counter will display at 30secs the remaining time, but if the user sets a counter with a one day timeout, the counter will display approximately every hour the remaining time.
So I did this, but I think it could largely be optimized with an exponential way..
Could you help me please
Here's my code:
TimeSpan time = TimeSpan.FromSeconds(Seconds - i);
string strTime;
if (Seconds > 30 && Seconds <= 300)
{
if (i == Seconds / 2)
{
strTime = time.ToString(#"mm\:ss");
account.Logger.LogMessage(LanguageManager.Translate("165"), LanguageManager.Translate("614", strTime));
}
}
else if (Seconds > 300 && Seconds <= 1800)
{
int firstOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds / 3));
int secondOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (2/3)));
if (i == firstOcc || i == secondOcc || i == Seconds - 60)
{
strTime = time.ToString(#"mm\:ss");
account.Logger.LogMessage(LanguageManager.Translate("165"), LanguageManager.Translate("614", strTime));
}
}
else if (Seconds > 1800 && Seconds <= 7200)
{
int firstOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds / 5));
int secondOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (2 / 5)));
int thirdOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (3 / 5)));
int fourthOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (4 / 5)));
if (i == firstOcc || i == secondOcc || i == thirdOcc || i == fourthOcc || i == Seconds - 60)
{
strTime = time.ToString(#"H\:mm\:ss");
account.Logger.LogMessage(LanguageManager.Translate("165"), LanguageManager.Translate("614", strTime));
}
}
else if (Seconds > 7200 && Seconds <= 43200)
{
int firstOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds / 8));
int secondOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (2 / 8)));
int thirdOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (3 / 8)));
int fourthOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (4 / 8)));
int fifthOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (5 / 8)));
int sixthOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (6 / 8)));
int seventhOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (7 / 8)));
if (i == firstOcc || i == secondOcc || i == thirdOcc || i == fourthOcc || i == fifthOcc || i == sixthOcc || i == seventhOcc || i == Seconds - 60)
{
strTime = time.ToString(#"H\:mm\:ss");
account.Logger.LogMessage(LanguageManager.Translate("165"), LanguageManager.Translate("614", strTime));
}
}
else if (Seconds > 43200)
{
Which is very redundant
I would use the log base 2. So the timers would be 32 seconds, 64 seconds, 128 seconds, 256 seconds, 512 seconds, 1024 seconds, 2048 seconds. So code would look something like this :
List<int> seconds = new List<int>() { 60, 200, 400, 600, 800, 2300, 3599 };
foreach (int second in seconds)
{
int timer = (second < 64)? 32 : (int)Math.Pow(2,(int)Math.Log(second, 2));
Console.WriteLine("Seconds : '{0}'; Timer : '{1}'", second, timer);
}
Console.ReadLine();
Here is an (untested) example of how you might go about refactoring your code to prevent repetition.
var time = TimeSpan.FromSeconds(seconds - i);
if (seconds <= 30)
{
// What to do here?
return;
}
int factor;
string format;
if (seconds <= 300)
{
factor = 2;
format = #"mm\:ss";
}
else if (seconds <= 1800)
{
factor = 3;
format = #"mm\:ss";
}
else if (seconds <= 7200)
{
factor = 5;
format = #"H\:mm\:ss";
}
else if (seconds <= 43200)
{
factor = 8;
format = #"H\:mm\:ss";
}
else
{
// Defaults when no other condition is met.
factor = 10;
format = #"H\:mm\:ss";
}
if (i == seconds - 60 || Enumerable.Range(1, factor - 1).Any(n => i == seconds / factor * n))
{
string timeDisplay = time.ToString(format);
account.Logger.LogMessage(LanguageManager.Translate("165"), LanguageManager.Translate("614", timeDisplay));
}

Write getter for Seconds of Fast Days

I have a function called getDayTimeParameter(), which gets the day parameter from 0 to 1. I also have two functions which are getters of hour and minute. I need to show time as hh:mm:ss. But the problem is I have no idea how to write getter for seconds. Thanks in advance!
public float getDayTimeParameter()
{
return System.DateTime.Now.Minute / 60f + System.DateTime.Now.Second / 3600f + System.DateTime.Now.Millisecond / 3600000f;
}
public int getHour()
{
int dayMinute = Mathf.RoundToInt(24 * 60 * getDayTimeParameter());
return Mathf.FloorToInt(dayMinute / 60f);
}
public int getMinute()
{
int dayMinute = Mathf.RoundToInt(24 * 60 * getDayTimeParameter());
int hour = getHour();
return Mathf.FloorToInt((dayMinute / 60f - hour) * 60f);
}
public int getSecond()
{
// What to do in here?
}
public string getFullTimeString()
{
int hour = getHour();
int minute = getMinute();
int second = getSecond();
string minutesString;
if (minute < 10)
{
minutesString = "0" + minute;
}
else {
minutesString = "" + minute;
}
string hoursString;
if (hour < 10)
{
hoursString = "0" + hour;
}
else
{
hoursString = "" + hour;
}
string secondsString;
if (second < 10)
{
secondsString = "0" + second;
}
else
{
secondsString = "" + second;
}
return hoursString + ":" + minutesString + ":" + secondsString;
}
Given that your getDayTimeParameter function returns 0-1, and a full day equals 1
then the following should give you accurate Hours, Minutes and Seconds.
public int getHour()
{
return Mathf.FloorToInt(getDayTimeParameter() * 24);
}
public int getMinute()
{
var hourSubtraction = getHour() * 60;
return Mathf.FloorToInt((getDayTimeParameter() * 1440) - hourSubtraction);
}
public int getSecond()
{
var hourSubtraction = getHour() * 3600;
var minuteSubtraction = getMinute() * 60;
return Mathf.FloorToInt((getDayTimeParameter() * 86400) - hourSubtraction - minuteSubtraction);
}
can't you just use DateTime.Now.ToString("hh:mm:ss") with its various options if necessary

Count of quarter between dates

I want to calculate the count of total quarters (of a year) in the given time span.
for example:
start date = 1-june -2009
end date = 18-july-2011
count should be = 10.
one more
start date = 4-Jan-2009
end date = 27-oct -2010
count =8.
I have not been able to get the correct result.
Your example is wrong: there are only 7 quarters between 4-Jan-2009 and 27-oct -2010
You could simply add a reference to the Microsoft.VisualBasic.dll to your project and use DateDiff:
VB:
Public Shared Function getQuartersBetween(ByVal d1 As Date, ByVal d2 As Date) As Int32
Return DateDiff(DateInterval.Quarter, d1, d2)
End Function
C#:
public static int getQuartersBetween(System.DateTime d1, System.DateTime d2)
{
return Microsoft.VisualBasic.DateAndTime.DateDiff(DateInterval.Quarter, d1, d2);
}
or you could write your own implementation:
public class Quarter
{
public static long GetQuarters(DateTime dt1, DateTime dt2)
{
double d1Quarter = GetQuarter(dt1.Month);
double d2Quarter = GetQuarter(dt2.Month);
double d1 = d2Quarter - d1Quarter;
double d2 = (4 * (dt2.Year - dt1.Year));
return Round(d1 + d2);
}
private static int GetQuarter(int nMonth)
{
if (nMonth <= 3)
return 1;
if (nMonth <= 6)
return 2;
if (nMonth <= 9)
return 3;
return 4;
}
private static long Round(double dVal)
{
if (dVal >= 0)
return (long)Math.Floor(dVal);
return (long)Math.Ceiling(dVal);
}
}
or in VB.NET:
Public Class Quarter
Public Shared Function GetQuarters(ByVal dt1 As DateTime, ByVal dt2 As DateTime) As Long
Dim d1Quarter As Double = GetQuarter(dt1.Month)
Dim d2Quarter As Double = GetQuarter(dt2.Month)
Dim d1 As Double = d2Quarter - d1Quarter
Dim d2 As Double = (4 * (dt2.Year - dt1.Year))
Return Round(d1 + d2)
End Function
Private Shared Function GetQuarter(ByVal nMonth As Integer) As Integer
If nMonth <= 3 Then
Return 1
End If
If nMonth <= 6 Then
Return 2
End If
If nMonth <= 9 Then
Return 3
End If
Return 4
End Function
Private Shared Function Round(ByVal dVal As Double) As Long
If dVal >= 0 Then
Return CLng(Math.Floor(dVal))
End If
Return CLng(Math.Ceiling(dVal))
End Function
End Class
Code for you : Try below code
public static void Main()
{
//Application.Run(new XmlTreeDisplay());
int monthdiuff = monthDifference(Convert.ToDateTime("01/04/09"), Convert.ToDateTime("10/27/10"));
Console.WriteLine(monthdiuff);
int totalQuater = (monthdiuff / 3) + (monthdiuff%3);
Console.WriteLine(totalQuater);
Console.ReadLine();
}
private static int monthDifference(DateTime startDate, DateTime endDate)
{
int monthsApart = 12 * (startDate.Year - endDate.Year) + startDate.Month - endDate.Month;
return Math.Abs(monthsApart);
}
Without some code to look over I can't help you find your exact problem.
If it were me I would probably find the difference between the dates in days, then divide by number of days in a quarter (91 or so). I'm sure that C# has some kind of date parsing module that can read in the dates as a string, giving you two objects that you could then subtract to find the difference in days.
This is one crude form of calculating the quarters based on your assumptions, you can choose to modify as it is it works good enough
DateTime dt1 = new DateTime(2009, 1, 1);// new DateTime(2009, 6, 1);
DateTime dt2 = new DateTime(2010, 10, 27);// new DateTime(2011, 7, 18);
if (dt1.Month < 4)
dt1 = new DateTime(dt1.Year,1,1);
else if (dt1.Month < 7)
dt1 = new DateTime(dt1.Year,4,1);
else if (dt1.Month < 10)
dt1 = new DateTime(dt1.Year,7,1);
else
dt1 = new DateTime(dt1.Year,10,1);
if (dt2.Month < 4)
dt2 = new DateTime(dt2.Year, 3, DateTime.DaysInMonth(dt2.Year, 3));
else if (dt2.Month < 7)
dt2 = new DateTime(dt2.Year, 6, DateTime.DaysInMonth(dt2.Year, 6));
else if (dt2.Month < 10)
dt2 = new DateTime(dt2.Year, 9, DateTime.DaysInMonth(dt2.Year, 9));
else
dt2 = new DateTime(dt2.Year, 12, DateTime.DaysInMonth(dt2.Year, 12));
TimeSpan ts = dt2 - dt1;
int quarters = (int) ts.TotalDays/90;
Console.WriteLine(quarters);
I am baselining the dates to the start and end of the quarters as you want and then assuming for 90 day quarter transforming the diff as int. Works for your mentioned examples,see if it suits you well enough
If the definition of a quarter is a 90-day difference, it's easy of course:
internal static int GetNumberOfQuarters(DateTime p_DtStart, DateTime p_DtEnd)
{
TimeSpan span = p_DtEnd.Subtract(p_DtStart);
return (int)span.TotalDays % 90;
}
But that's not what you're looking for. What about this (not tested but you'll get the idea)
internal static class DateTimeTools
{
internal static int GetNumberOfQuartersBetweenDates(DateTime startDate, DateTime endDate)
{
int iYearStart, iYearEnd, iMonthStart, iMonthEnd, iDayStart, iDayEnd;
iYearStart = startDate.Year;
iYearEnd = endDate.Year;
iMonthStart = startDate.Month;
iMonthEnd = endDate.Month;
iDayStart = startDate.Day;
iDayEnd = endDate.Day;
int iYearDiff, iQuarterDiff, iDayDiff;
iYearDiff = iYearEnd - iYearStart;
iQuarterDiff = iMonthEnd % 3 - iMonthStart % 3;
iDayDiff = iDayEnd - iDayStart;
int iNumOfQuarters = 0;
// at least a year difference?
if ((iYearDiff > 0 && iQuarterDiff > 0) || iYearDiff > 0 && iQuarterDiff == 0 && iDayDiff >= 0)
{
iNumOfQuarters = iYearDiff * 4 + iQuarterDiff;
}
// at least a quarter difference?
// within different years
if ((iYearDiff > 0 && iQuarterDiff <= 0)) // eg, dec 2010 - feb 2011 iYearDiff 1 iQuarterDiff -3
{
if ((iQuarterDiff == -3 && iDayDiff >= 0) || iQuarterDiff > -3)
{
iNumOfQuarters = iQuarterDiff + 4;
}
}
// within the same year
if (iYearDiff == 0 && iQuarterDiff > 0)
{
if ((iQuarterDiff == 1 && iDayDiff >= 0) || iQuarterDiff > 1)
{
iNumOfQuarters = iQuarterDiff;
}
}
return iNumOfQuarters;
}
}
Regards,
Nico
public static string GetQuarter(this DateTime date)
{
var quarterList = new List<string>();
if (date.Month >= 1 && date.Month <= 3)
return "Q1";
else if (date.Month >= 4 && date.Month <= 6)
return "Q1,Q2";
else if (date.Month >= 7 && date.Month <= 9)
return "Q1,Q2,Q3";
else
return "Q1,Q2,Q3,Q4";
}
This too can be used as an extension method if you are expecting to get a list of Quarters, You can later on use GetQuarter().Split(new[] { ',' }).Count() to get the count.
Easy formula to get quarters difference:
{
int firstQuarter = getQuarter(first);
int secondQuarter = getQuarter(second);
return 1 + Math.Abs(firstQuarter - secondQuarter);
}
private static int getQuarter(DateTime date)
{
return (date.Year * 4) + ((date.Month - 1) / 3);
}

Pretty Date Text in Flex / Flash / Java / C#

Is there a free library or class for formatting a date in a pretty way such as "5 minutes ago" or "yesterday"?
I'd be satisfied with the same code in another language that I could port to Actionscript (like Java or C#)
would this help? Should be very easy to port to AS3.
/*
* JavaScript Pretty Date
* Copyright (c) 2008 John Resig (jquery.com)
* Licensed under the MIT license.
*/
// Takes an ISO time and returns a string representing how
// long ago the date represents.
function prettyDate(time){
var date = new Date((time || "").replace(/-/g,"/").replace(/[TZ]/g," ")),
diff = (((new Date()).getTime() - date.getTime()) / 1000),
day_diff = Math.floor(diff / 86400);
if ( isNaN(day_diff) || day_diff < 0 || day_diff >= 31 )
return;
return day_diff == 0 && (
diff < 60 && "just now" ||
diff < 120 && "1 minute ago" ||
diff < 3600 && Math.floor( diff / 60 ) + " minutes ago" ||
diff < 7200 && "1 hour ago" ||
diff < 86400 && Math.floor( diff / 3600 ) + " hours ago") ||
day_diff == 1 && "Yesterday" ||
day_diff < 7 && day_diff + " days ago" ||
day_diff < 31 && Math.ceil( day_diff / 7 ) + " weeks ago";
}
// If jQuery is included in the page, adds a jQuery plugin to handle it as well
if ( typeof jQuery != "undefined" )
jQuery.fn.prettyDate = function(){
return this.each(function(){
var date = prettyDate(this.title);
if ( date )
jQuery(this).text( date );
});
};
I'm using this Relative Time code for a Twitter widget I'm working on. It's PHP, but nothing feature-specific so a port should be pretty easy.
I ended up writing my own.
/**
* Takes a Date object and returns a string in the format
* "X UNITS ago" where X is a number and UNITS is a unit of
* time. Also has some other strings like "yesterday".
*
* #author Mims Wright (with thanks to John Resig)
*
* #param date The date to convert to a past string.
* #param now Optional time to compare against. Default will be the present.
*/
public function getTimeElapsedString(date:Date, now:Date = null):String {
const SEC_PER_MINUTE:int = 60;
const SEC_PER_HOUR:int = SEC_PER_MINUTE * 60;
const SEC_PER_DAY:int = SEC_PER_HOUR * 24;
const SEC_PER_WEEK:int = SEC_PER_DAY * 7;
const SEC_PER_MONTH:int = SEC_PER_DAY * 30;
const SEC_PER_YEAR:int = SEC_PER_MONTH * 12;
// if now isn't defined, make it a new Date object (the present)
if (!now) { now = new Date(); }
// don't use secondsElapsed here because the values are
// huge so they use uints and are never negative
if (now.time < date.time) { return "in the future"; }
// get the difference in seconds between the two values.
var secondsElapsed:uint = Math.floor((now.time - date.time) / 1000);
// seconds
if (secondsElapsed < SEC_PER_MINUTE) { return "just now"; }
// minutes
if (secondsElapsed < SEC_PER_HOUR) {
var minutes:int = int(secondsElapsed / SEC_PER_MINUTE);
return formatAgoString(minutes, "minute");
}
// hours
if (secondsElapsed < SEC_PER_DAY) {
var hours:int = int(secondsElapsed / SEC_PER_HOUR);
return formatAgoString(hours, "hour");
}
// days
if (secondsElapsed < SEC_PER_WEEK) {
var days:int = int(secondsElapsed / SEC_PER_DAY);
if (days == 1) { return "yesterday"; }
return formatAgoString(days, "day");
}
// weeks
if (secondsElapsed < SEC_PER_MONTH) {
var weeks:int = int(secondsElapsed / SEC_PER_WEEK);
return formatAgoString(weeks, "week");
}
// months
if (secondsElapsed < SEC_PER_YEAR) {
var months:int = int(secondsElapsed / SEC_PER_MONTH);
return formatAgoString(months, "month");
}
// years
return "more than a year ago";
// Returns a string in the format "count unit(s) ago"
function formatAgoString(count:int, unit:String):String {
return count + " " + unit + (count > 1 ? "s" : "") + " ago";
}
}
Going to try PrettyTime (github) in Java now. Multi-language and customizable.

Categories

Resources