ISO week number
От: Кодт Россия  
Дата: 05.07.04 13:26
Оценка:
Помогите с формулой, пожалуйста. Весь день головой об стол стучу, что-то никак.

Дано: дата (день,месяц,год).

Номер недели по ISO — это число 1..53
неделя начинается с понедельника
первая неделя должна включать в себя первый четверг года
нулевая неделя — это 52 или 53 (т.е. относится к прошлому году)

Можно пользоваться WinAPI.
Перекуём баги на фичи!
Re: ISO week number
От: Faust Россия  
Дата: 05.07.04 13:44
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Помогите с формулой, пожалуйста. Весь день головой об стол стучу, что-то никак.


К>Дано: дата (день,месяц,год).


К>Номер недели по ISO — это число 1..53

К>неделя начинается с понедельника
К>первая неделя должна включать в себя первый четверг года
К>нулевая неделя — это 52 или 53 (т.е. относится к прошлому году)

К>Можно пользоваться WinAPI.



SYSTEMTIME    SystemTime1;
SYSTEMTIME    SystemTime2;
FILETIME    FileTime1;
FILETIME    FileTime2;
double        dNanoSec;
int            iDay;

// Получили текущее системное время
GetLocalTime(&SystemTime1); 
SystemTime2 = SystemTime1;
//Задали "1января текущего года"
SystemTime2.wMonth=1; SystemTime2.wDay=1;
SystemTime2.wHour=0; SystemTime2.wMinute=0; SystemTime2.wSecond=0;
//Опред.число Тик с 1601 года
SystemTimeToFileTime(&SystemTime1, &FileTime1);
SystemTimeToFileTime(&SystemTime2, &FileTime2);
//Получаем разницу в тиках 2-х дат
dNanoSec = static_cast<double> ((FileTime1.dwHighDateTime - FileTime2.dwHighDateTime) *
    0xFFFFFFFF + (FileTime1.dwLowDateTime - FileTime2.dwLowDateTime));
//Определяем текущий день года
iDay = (int) ((dNanoSec / ((double) 24 * 36000000000)) + 1);
Дальше считай сам...
Мой компьютер прогоняет бесконечный цикл за 9 секунд, но, мне кажется, он мог бы сделать это быстрее...
Re[2]: ISO week number
От: Кодт Россия  
Дата: 05.07.04 13:56
Оценка:
Здравствуйте, Faust, Вы писали:

F>//Определяем текущий день года

F>iDay = (int) ((dNanoSec / ((double) 24 * 36000000000)) + 1);

F>Дальше считай сам...

День года я умею получить. Даже без плавающей арифметики.

Как получить номер недели, с учётом всех вышеупомянутых правил? И с учётом того, что в локали может стоять первый день недели — воскресенье, среда, чёрт-знает-что? А ISO-шная неделя — строго с понедельника.
Перекуём баги на фичи!
Re[3]: ISO week number
От: Faust Россия  
Дата: 05.07.04 14:12
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Как получить номер недели, с учётом всех вышеупомянутых правил? И с учётом того, что в локали может стоять первый день недели — воскресенье, среда, чёрт-знает-что? А ISO-шная неделя — строго с понедельника.

Блин, может я чего не понимаю.
1. Берем за отправную точку текущий год.
2. Расчитываем порядковый номер необходимого нам дня года.
3. Вычитаем из него количетво дней от 1 января до первого понедельника текущего года.
4. Делим полученное число на 7.
5. Если нужно сделать расчет на следующий год или на предыдущий, то вносишь соответствующие поправки в п.3, т.е. для следующего года +1, для предыдущего -2, т.к. этот год високосный.
Мой компьютер прогоняет бесконечный цикл за 9 секунд, но, мне кажется, он мог бы сделать это быстрее...
Re: ISO week number
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 05.07.04 14:40
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Помогите с формулой, пожалуйста. Весь день головой об стол стучу, что-то никак.


К>Дано: дата (день,месяц,год).


К>Номер недели по ISO — это число 1..53

К>неделя начинается с понедельника
К>первая неделя должна включать в себя первый четверг года
К>нулевая неделя — это 52 или 53 (т.е. относится к прошлому году)

К>Можно пользоваться WinAPI.

Прошу прощения может не в тему. По сути нужно найти дату первой недели

Накидаю формул из Net может пригодится

 private static long DateToTicks(int year, int month, int day)
{
 int[] array1;
int num1;
int num2;
if (((year >= 1) && (year <= 9999)) && ((month >= 1) && (month <= 12)))
{
 array1 = (DateTime.IsLeapYear(year) ? DateTime.DaysToMonth366 : DateTime.DaysToMonth365);
if ((day >= 1) && (day <= (array1[month] - array1[(month - 1)])))
{
 num1 = (year - 1);
num2 = (((((((num1 * 365) + (num1 / 4)) - (num1 / 100)) + (num1 / 400)) + array1[(month - 1)]) + day) - 1);
return (((long) num2) * 864000000000);
 
}
 
}
throw new ArgumentOutOfRangeException(Environment.GetResourceString("ArgumentOutOfRange_BadYearMonthDay"));
 
}





long в NET Int64

 public DayOfWeek DayOfWeek
{
 get
{
 return ((int) (((this.ticks / 864000000000) + ((long) 1)) % ((long) 7)));
 
}
 
}



public int get_DayOfYear()
{
 return this.GetDatePart(1);
 
}

private int GetDatePart(int part)
{
 int num1 = ((int) (this.ticks / 864000000000));
int num2 = (num1 / 146097);
num1 -= (num2 * 146097);
int num3 = (num1 / 36524);
if (num3 == 4)
{
 num3 = 3;
 
}
num1 -= (num3 * 36524);
int num4 = (num1 / 1461);
num1 -= (num4 * 1461);
int num5 = (num1 / 365);
if (num5 == 4)
{
 num5 = 3;
 
}
if (part == 0)
{
 return (((((num2 * 400) + (num3 * 100)) + (num4 * 4)) + num5) + 1);
 
}
num1 -= (num5 * 365);
if (part == 1)
{
 return (num1 + 1);
 
}
bool flag1 = ((num4 != 24) ? ((num5 != 3) ? 0 : 1) : (num3 == 3));
int[] array1 = (flag1 ? DateTime.DaysToMonth366 : DateTime.DaysToMonth365);
int num6 = (num1 >> 6);
while ((num1 >= array1[num6]))
{
 num6 += 1;
 
}
if (part == 2)
{
 return num6;
 
}
return ((num1 - array1[(num6 - 1)]) + 1);
 
}


public int get_DayOfYear()
{
 return this.GetDatePart(1);
 
}



private int GetDatePart(int part)
{
 int num1 = ((int) (this.ticks / 864000000000));
int num2 = (num1 / 146097);
num1 -= (num2 * 146097);
int num3 = (num1 / 36524);
if (num3 == 4)
{
 num3 = 3;
 
}
num1 -= (num3 * 36524);
int num4 = (num1 / 1461);
num1 -= (num4 * 1461);
int num5 = (num1 / 365);
if (num5 == 4)
{
 num5 = 3;
 
}
if (part == 0)
{
 return (((((num2 * 400) + (num3 * 100)) + (num4 * 4)) + num5) + 1);
 
}
num1 -= (num5 * 365);
if (part == 1)
{
 return (num1 + 1);
 
}
bool flag1 = ((num4 != 24) ? ((num5 != 3) ? 0 : 1) : (num3 == 3));
int[] array1 = (flag1 ? DateTime.DaysToMonth366 : DateTime.DaysToMonth365);
int num6 = (num1 >> 6);
while ((num1 >= array1[num6]))
{
 num6 += 1;
 
}
if (part == 2)
{
 return num6;
 
}
return ((num1 - array1[(num6 - 1)]) + 1);
 
}
... << RSDN@Home 1.1.0 stable >>
и солнце б утром не вставало, когда бы не было меня
Re: ISO week number
От: conraddk Россия  
Дата: 05.07.04 16:48
Оценка: 36 (1)
Здравствуйте, Кодт, Вы писали:

К>Помогите с формулой, пожалуйста. Весь день головой об стол стучу, что-то никак.


К>Дано: дата (день,месяц,год).


К>Номер недели по ISO — это число 1..53

К>неделя начинается с понедельника
К>первая неделя должна включать в себя первый четверг года
К>нулевая неделя — это 52 или 53 (т.е. относится к прошлому году)

К>Можно пользоваться WinAPI.


Предположим, что мы умеем получать день недели в виде 0,1,2..6 (0 — понедельник, 6 — воскресенье) и день года, тоже индексированный от нуля. Тогда вроде бы должно работать примерно следующее:
// дано d, m, y
// день недели на данную дату
int curDOW = DayOfWeek( d, m, y );
// день недели 1 января данного года
int baseDOW = DayOfWeek( 1, 1, y );
// день в году
int curDOY = DayOfYear( d, m, y );
// если год начинается с пн, вт, ср, чт, 
// то 1 января - первая неделя, иначе - нулевая
int baseWeek = baseDOW<4 ? 1 : 0;
// грубо: номер нашей недели - это 
// номер недели 1 января + количество целых недель
int isoWeek = baseWeek + curDOY / 7;
// коррекция: если данный день раньше в неделе, чем 1 января, 
// то на самом деле неделя уже другая (следующая)
if( curDOW < baseDOW )
  ++isoWeek;
... << RSDN@Home 1.1.3 stable >>
Все на свете должно происходить медленно и неправильно...
Re[2]: ISO week number
От: conraddk Россия  
Дата: 05.07.04 16:51
Оценка:
Да, забыл. Еще нужна коррекция нулевой недели, если она получается в ответе. Для этого тем же самым способом получаем номер недели 31.12 предыдущего года — это и будет ответ.
... << RSDN@Home 1.1.3 stable >>
Все на свете должно происходить медленно и неправильно...
Re: ISO week number
От: Шахтер Интернет  
Дата: 06.07.04 00:32
Оценка: 24 (2)
Здравствуйте, Кодт, Вы писали:

К>Помогите с формулой, пожалуйста. Весь день головой об стол стучу, что-то никак.


К>Дано: дата (день,месяц,год).


К>Номер недели по ISO — это число 1..53

К>неделя начинается с понедельника
К>первая неделя должна включать в себя первый четверг года
К>нулевая неделя — это 52 или 53 (т.е. относится к прошлому году)

К>Можно пользоваться WinAPI.


МММ. Ну давай чуть-чуть порассуждаем. Переводим дату в номер дня в году. Все номера дней занимают отрезок 1-365 или 1-366 для високосного года. Теперь рассмотрим первые семь дней 1-7. Один из этих дней (и только один) -- четверг. Пусть это день номер k. От чего зависит это число? От года и больше ни от чего. Надо научиться его вычислять. Ну а дальше просто. Номер недели для дня k -- 1, потому что это первый четверг в году. Если теперь у нас день номер k+7*n, то его номер недели -- 1+n. Если k+1+7*n (пятница), k+2+7*n (суббота), k+3+7*n (воскресенье), то тоже 1+n. А вот для
k+4+7*n (понедельник) -- уже 2+n. Короче, n+1 я неделя -- это [k-3+7*n,k+3+7*n]. Значит, день номер l принадлежит (l+10-k)/7 й неделе.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[3]: ISO week number
От: xWanderer Россия  
Дата: 24.03.06 15:11
Оценка:
Здравствуйте, conraddk, Вы писали:

C>Да, забыл. Еще нужна коррекция нулевой недели, если она получается в ответе. Для этого тем же самым способом получаем номер недели 31.12 предыдущего года — это и будет ответ.


А как насчет обратной задачи? имеется например 31.12. как узнать к какой неделе относится эта дата, к 52-й неделе этого года или к 1-й неделе следующего года? именно по календарю!!! а не по порядковому номеру недели в году.
т.к. по вышеизложенным алгоритмам 31.12 и 01.01 находящиеся в одной неделе выдадут разные номера нелеь если 01.01 — это 1-я неделя.
Re[4]: ISO week number
От: conraddk Россия  
Дата: 28.03.06 04:14
Оценка:
Здравствуйте, xWanderer, Вы писали:

W>А как насчет обратной задачи? имеется например 31.12. как узнать к какой неделе относится эта дата, к 52-й неделе этого года или к 1-й неделе следующего года? именно по календарю!!! а не по порядковому номеру недели в году.

Не понял выделенное. Кстати, почему задача обратная? Та же самая: по дате надо узнать неделю.

W>т.к. по вышеизложенным алгоритмам 31.12 и 01.01 находящиеся в одной неделе выдадут разные номера нелеь если 01.01 — это 1-я неделя.

Из определения ISO week number
Автор: Кодт
Дата: 05.07.04
так и получается. 31.12 в этом случае в последней неделе старого года, а 01.01 — в первой неделе нового года. Если нужно относить 31.12 в такой ситуации к первой неделе нового года (что об этом думает ISO? ), добавляем еще одну коррекцию. Такое может произойти в следующих случаях:
пн вт ср чт пт сб вс 
29 30 31  1  2  3  4
30 31  1  2  3  4  5
31  1  2  3  4  5  6

Условие:
if ( m==12 && d-29>=curDOW )
    isoWeek = 1;

Д.К. << RSDN@Home 1.1.4 stable rev. 510>>
Все на свете должно происходить медленно и неправильно...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.