[AS3] Få ut veckonumret från ett datum

Trädvy Permalänk
Medlem
Plats
Göteborg
Registrerad
Jun 2004

[AS3] Få ut veckonumret från ett datum

Kämpar med en liten funktion som inte vill ge mig rätt veckonummer... jag har följt en instruktion jag hittade på Wikipedia (ISO-vecka). Har googlat järnet men ingen funktion jag hittat ger mig rätt svar, hur krångliga algoritmerna än är.

Edit: Det fungerar nästan nu. Men inte alla ISO-datum, t.ex. 2007-12-31 ska bli vecka 01. Jag jobbar på det... tips välkomna.

function getWeek(d:Date):Number { var dayOfYear:Number = getDayOfYear(d); var weekDay:Number = d.day; if (weekDay == 0) weekDay = 7; var week:Number = Math.floor((dayOfYear - weekDay + 10) / 7); if (week == 53 && weekDay > 3) week = 1; else if (week == 0) { if (getWeek(new Date(d.fullYear - 1, 11, 31)) == 1) week = 53; else week = 52; } return week; }

(getDayOfYear finns här och verkar funka)

Trädvy Permalänk
Medlem
Plats
Exil i huvudstaden
Registrerad
Jul 2004

http://www.cpearson.com/excel/weeknum.htm

Visserligen VB-kod men det bör du kunna översätta. Det är de två nedersta funktionerna på den sidan jag syftar på.

Crap.

Trädvy Permalänk
Medlem
Plats
Göteborg
Registrerad
Jun 2004
Citat:

Ursprungligen inskrivet av Morr
http://www.cpearson.com/excel/weeknum.htm

Visserligen VB-kod men det bör du kunna översätta. Det är de två nedersta funktionerna på den sidan jag syftar på.

Tackar! Har översatt den nedersta nu iaf:

function getFirstMonday(year:Number):Date { var newYear:Date = new Date(year, 0, 1); var weekDay:Number = newYear.day; if (weekDay == 0) weekDay = 7; weekDay = (weekDay - 1) % 7; if (weekDay < 4) newYear.date -= weekDay; else newYear.date -= weekDay + 7; // Kommer inte på varför detta skulle behövas... // VBA är inte min starka sida. Men det funkar iaf. if (newYear.month == 11 && newYear.date < 25) newYear.date += 7; return newYear; }

Börjar översätta funktionen över nu... eller kompletterar min med den här.

Trädvy Permalänk
Medlem
Plats
Göteborg
Registrerad
Jun 2004

Hittade en som var bra mycket kortare, men fungerar fortfarande inte för alla datum... känns som att jag ska ge upp det här snart. Jävla ISO-veckor. Inget av de datum-bibliotek jag provat klarar av dem heller.

Denna funkar alltså inte heller, men jag använder den så länge, mest på grund av rekursiviteten:

function getWeek(d:Date):Number { var f : Number = 2 - new Date(d.fullYear, 0, 1).day; if (f < 0) f += 7; var m : Date = new Date(d.fullYear, 0, f); var week : Number = Math.floor(Math.floor((d.time - m.time) / 86400000) / 7) + 1; if (week == 0) week = getWeek(new Date(d.fullYear - 1, 11, 31)); if (week > 52) week -= 52; return week; }

Trädvy Permalänk
Medlem
Plats
Göteborg
Registrerad
Jun 2004

Ursäkta bump, men nu har jag en fungerande lösning på problemet. Detta är såvitt jag kan se den enda fungerande lösningen för ActionScript som finns tillgänglig på nätet. Jag översatte denna C#-lösning och här är resultatet:

function getIsoWeekNumber(dt:Date):Number { var week1:Date; var isoYear:Number = dt.fullYear; if (dt >= new Date(isoYear, 11, 29)) { week1 = getIsoWeekOne(isoYear + 1); if (compareDates(dt, week1) == -1) week1 = getIsoWeekOne(isoYear); else isoYear++; } else { week1 = getIsoWeekOne(isoYear); if (compareDates(dt, week1) == -1) week1 = getIsoWeekOne(--isoYear); } return Math.floor(((isoYear * 100) + datesDiff(dt, week1) / 7 + 1) % 100); } function getIsoWeekOne(Year:Number):Date { var dt:Date = new Date(Year, 0, 4); var dayNumber:Number = dt.day; if (dayNumber == 0) dayNumber = 7; dt.date += 1 - dayNumber; return dt; } function datesDiff(d1:Date, d2:Date):Number { return Math.floor(Math.abs((d1.time - d2.time) / 86400000)); } function compareDates(d1:Date, d2:Date):Number { var date1Timestamp:Number = d1.getTime(); var date2Timestamp:Number = d2.getTime(); var result:Number = -1; if (date1Timestamp == date2Timestamp) result = 0; else if (date1Timestamp > date2Timestamp) result = 1; return result; }

Trädvy Permalänk
Medlem
Registrerad
Nov 2004

4 Januari är alltid i vecka 1, så man kan räkna "baklänges" utifrån det vilket också koden ovanför verkar göra.

Trädvy Permalänk
Medlem
Plats
Göteborg
Registrerad
Jun 2004
Citat:

Ursprungligen inskrivet av Gramner
4 Januari är alltid i vecka 1, så man kan räkna "baklänges" utifrån det vilket också koden ovanför verkar göra.

Hur man räknar ut veckonumret har aldrig varit ett problem i tankar och ord Definitionen och algoritmen är enkel, men blir programmatiskt omständlig.

Trädvy Permalänk
Medlem
Plats
Exil i huvudstaden
Registrerad
Jul 2004

Ok, så bra. Annars har jag en lösning också - Jag översatte VB-koden jag länkade och vad jag kan se fungerar det.

Hjälpfunktionen fick skrivas om lite då VB-lösningen inte gick att direktöversättas. Vad jag gillar med denna lösning är att den är hyfsat pedagogisk och lättförstådd. Men i slutändan är ju korrektheten viktigast

Jag kommenterade koden med, men döpte inte om (de ganska kassa) variabelnamnen så man kan se hur de relaterar till orginalkoden enklare.

// // Return the date of the first monday of a year. That is, // the first monday of week one. This means the date can be // on the previous year. // private DateTime YearStart(int whichYear) { DateTime newYear = new DateTime(whichYear, 1, 1); int weekDay = (newYear.DayOfWeek - DayOfWeek.Monday) % 7; if (weekDay < 4) { return newYear.AddDays(-weekDay); } else { return newYear.AddDays(-weekDay + 7); } } /// <summary> /// Return ISO 8601 week number of a given year. /// Since a date of a specific year can have a week number /// belonging to the previuos or next year, the option to /// include year is provided. See parameter incudeYear /// Code translated from www.cpearson.com/excel/weeknum.htm /// </summary> /// <param name="anyDate">The date to get week number of</param> /// <param name="includeYear">Prefix with year if true</param> /// <returns>ISO 8601 week number</returns> private int IsoWeek(DateTime anyDate, bool includeYear) { int thisYear = anyDate.Year; // Date of first monday for previous, this and next year DateTime thisYearStart = YearStart(thisYear); DateTime previousYearStart = YearStart(thisYear - 1); DateTime nextYearStart = YearStart(thisYear + 1); // Result int yearNum; int isoWeekNum; // Date is next year? if (anyDate >= nextYearStart) { isoWeekNum = (anyDate - nextYearStart).Days / 7 + 1; yearNum = thisYear + 1; } // Date is previous year? else if (anyDate < thisYearStart) { isoWeekNum = (anyDate - previousYearStart).Days / 7 + 1; yearNum = thisYear - 1; } // ...date is this year else { isoWeekNum = (anyDate - thisYearStart).Days / 7 + 1; yearNum = thisYear; } // Do we return year as well? if (includeYear) { // Format: (Y)YWW return (yearNum % 100) * 100 + isoWeekNum; } else { // Format: (W)W return isoWeekNum; } }

Crap.

Trädvy Permalänk
Medlem
Plats
Göteborg
Registrerad
Jun 2004
Citat:

Ursprungligen inskrivet av Morr
Ok, så bra. Annars har jag en lösning också - Jag översatte VB-koden jag länkade och vad jag kan se fungerar det.

Jag hade redan hittat fungerande kod för C#, problemet var att jag inte fick den att fungera i AS3. Förrän i min senaste post.

Trädvy Permalänk
Medlem
Plats
Exil i huvudstaden
Registrerad
Jul 2004

Jag såg det men då hade jag redan hunnit skriva lösningen. Så jag klistrade in den då den kanske hjälper någon annan i framtiden.

Och som sagt, den är hyfsat pedagogisk. För som du säger - algoritmen i sig är enkel men en lösning i kod som är lika enkel är svår att hitta. Den jag bifogade är nog den bästa jag sett hittills.

AS3 har jag inte programmerat. Känns som det ligger nära till hands att översätta från C# till AS3 vad jag kan se på din kod.

Om du tycker veckonummer är omständigt, prova då på att räkna ut månens cykler... Säg till om du hittar en bra och fungerande lösning som inte är asful

Crap.

Trädvy Permalänk
Medlem
Plats
Here & There
Registrerad
Okt 2008

En annan C# lösning (for future reference),

Int16? WeekOfYear = null;
DateTime day; //Sätt datum här
WeekOfYear = Calendar.GetWeekOfYear(day, System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);

What I'm watching thru myTV
[Annons bortredigerad av moderator]

Trädvy Permalänk
Medlem
Plats
Exil i huvudstaden
Registrerad
Jul 2004

Nice! Komplett blir det (då Calendar är abstract iaf i mitt VS):

GregorianCalendar cal = new GregorianCalendar(); int wnum = cal.GetWeekOfYear(date, System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);

Crap.

Trädvy Permalänk
Medlem
Plats
Exil i huvudstaden
Registrerad
Jul 2004

Hmm, får inte GetWeekOfYear ovan att stämma. Några exempel:

2001-12-31 så returnerar den vecka 53, men det skall vara 1 enligt den kalender jag brukar använda online, och enligt metoden jag klippte in.

Samma typ av diff får jag på bl.a.:

2002-12-31, 2003-12-31, 2007-12-31 samt 2008-12-31 för att ta några exempel.

Har jag bommat något?

Crap.