2010-02-03 12 views
5

Pracuję dla siebie, jestem samozatrudnionym programistą iw rezultacie nie mam luksusu recenzji kodu lub umiejętności poprawy w oparciu o programowanie peer. Zamierzam użyć tego jako ćwiczenia, aby sprawdzić, czy społeczność StackOverflow może pomóc w przejrzeniu prostej metody, którą napisałem;Refactor for Speed: Konwertuj na datę

internal static DateTime CONVERT_To_DateTime(int binDate) 
    { 
     // 3/10/2008 = 1822556159 
     // 2/10/2008 = 1822523391 
     // 1/10/2008 = 1822490623 
     // 30/09/2008 = 1822392319 
     // 29/09/2008 = 1822359551 

     // September 30th 2008 
     // 1822392319 = 0x6c9f7fff 
     // 0x6c = 108 = 2008 (based on 1900 start date) 
     // 0x9 = 9 = September 
     // 0xf7fff - take top 5 bits = 0x1e = 30 

     // October 1st 2008 
     // 1822490623 = 0x6ca0ffff 
     // 0 x6c = 108 = 2008 
     // 0 xa = 10 = October 
     // 0x0ffff - take top 5 bits = 0x01 = 1 

     // OR using Binary (used by this function) 
     // a = 1822556159 (3/10/2008) 
     // 1101100 1010 00011 111111111111111 

     // b = 1822523391 (2/10/2008) 
     // 1101100 1010 00010 111111111111111 

     // c = 1822490623 (1/10/2008) 
     // 1101100 1010 00001 111111111111111 

     // D = 1822392319 (30/09/2008) 
     // 1101100 1001 11110 111111111111111 

     // Excess 111111 are probably used for time/seconds which 
     // we do not care for at the current time 

     var BaseYear = 1900; 

     // Dump the long date to binary 
     var strBinary = Convert.ToString(binDate); 

     // Calculate the year 
     var strBYear = strBinary.Substring(0, 7); 
     var iYear = Convert.ToInt32(strBYear, 2) + BaseYear; 

     // Calculate the month 
     var strBMonth = strBinary.Substring(7, 4); 
     var iMonth = Convert.ToInt32(strBMonth, 2); 

     // Calculate the day 
     var strBDay = strBinary.Substring(11, 5); 
     var iDay = Convert.ToInt32(strBDay, 2); 

     // ensure that month and day have two digits 
     var strDay = iDay < 10 ? "0" + iDay : iDay.ToString(); 
     var strMonth = iMonth < 10 ? "0" + iMonth : iMonth.ToString(); 

     // Build the final date 
     var convertedDate = iYear + strMonth + strDay; 

     return DateTime.ParseExact(convertedDate, "yyyyMMdd", null); 
    } 

Jest to metoda, która przyjmuje numeryczną reprezentację daty i konwertuje ją na DateTime DataType. Chciałbym, aby ta metoda została sprawdzona, aby osiągnąć jak najszybszy czas wykonania, ponieważ jest wykonywany w pętli.

Wszelkie uwagi na temat metody są mile widziane, ponieważ będzie to dla mnie ćwiczenie. Czekam na niektóre odpowiedzi.

+0

Powinieneś zawsze oznaczać takie pytania językiem programowania, aby pomóc ludziom go znaleźć. – unwind

+0

Operacje binarne działają szybciej przy użyciu maski bitowej i metody zmiany bitów – tooleb

+0

FYI, pomijając wiodące 0 w liczbach binarnych, może być mylące dla innych programistów. Można oczekiwać, że wszystkie 32 bity będą reprezentowane. –

Odpowiedz

4

Robisz manipulacje ciągami. To prawdziwy zabójca wydajności, gdy używa się go w ciasnych pętlach.

static DateTime ToDateTime(int value) 
    { 
     var year = (int)((value & 0xff000000) >> 24); 
     var month = (value & 0xf00000) >> 20; 
     var day = (value & (0xf8000)) >> 15; 

     return new DateTime(1900 + year, month, day); 
    } 

Oto jak to zrobić. Po pierwsze, wziąć 1822490623 i przekonwertować go na binarny:

0110 1100 1010 0000 1111 1111 1111 1111 

Jest to maska ​​dla roku:

f f 0 0 0 0 0 0 

To dla miesiąca:

0 0 f 0 0 0 0 0 

A to za dzień:

0 0 0 f 8 0 0 0 

Wartość "Rok" musi być przesunięty w prawo o 6 * 4 bitów, "miesiąc" - o 5 * 4, i "dzień" - o 3 * 4 + 3 bitów.

+0

, więc jak można napisać tę metodę dla lepszej wydajności? – Phillis

+0

ale jeśli jesteśmy trochę zmienni, dlaczego nie przesuniemy się w lewo << ??? – Phillis

+0

thx .. Udało mi się to uzyskać – Phillis

10

Zamiast konwersji na sznurku, a następnie do liczb całkowitych, a następnie do łańcucha, a następnie do tej pory, po prostu liczby całkowite poprzez przesuwanie i maskowanie i tworzyć wartość DateTime bezpośrednio z wartości:

binDate >>= 15; 
int day = binDate & 31; 
binDate >>= 5; 
int month = binDate & 15; 
binDate >>= 8; 
int year = binDate + 1900; 
return new DateTime(year, month, day); 
+0

+1 za lepsze i bardziej kompletne niż moje. :) (Chociaż przyznaję, że wolę hex niż dziesiętny dla bitmasków.) –

+0

Piękny przykład ciasnego przesuwania bitów i maskowania w C#, dobrze zrobione. Jestem z Gregiem przy użyciu hexa - jest bardziej przejrzysty i kompiluje to samo. Naprawiono matematykę z roku. – richardtallent

+0

jednak nie rozwiązuje się z "rokiem", tzn. Rok jest nieprawidłowy – Phillis

4

Witamy w społeczności, Phillis. :)

Anton ma rację, twoje manipulacje ciągami będą powolne. Ponieważ wygląda na to, że używasz tego parametru jako pola bitowego, sugerowałbym przejrzenie różnych (znacznie szybszych) operatorów bitów: < <, >>, &, | i ~. Wygląda na to, że próbujesz manipulować binarnie, więc używaj operatorów do tego zbudowanych.

E.g. (niesprawdzony, tuż przy mankiecie):

Zaczynasz od wartości 0x6c9f7fff. Bajt wysokiego rzędu składa się na rok. Aby zamaskować się wszystkiego, co nie jest rok, zrób coś takiego:

int year = ((binDate & 0xFF000000) >> 24) + BaseYear; 

Podobnie, kolejne 4 bity są miesiące, więc:

int month = (binDate & 0x00F00000) >> 20; 
int date = (binDate & 0x000F8000) >> 15; 
return new DateTime(year, month, date); 
-2

będę sugerować Ci znaleźć C/Kod C++, który wykonuje podobną pracę; następnie przesłać go do C#