Jak już wspominałem kiedyś, pracuję ostatnio nad oprogramowaniem przeniesionym z LINCaW, COBOLaW i ALGOLaW na Jave + Oracle. Programy zostały przeniesione przez specjalne oprogramowanie migrujące, ale w praktyce okazało się, że pracują znacznie wolniej niż oryginalne. Dlatego też obecnie przepisujemy logikę od nowa na Javę. W każdym bądź…

Pamiętamy co to jest „Problem roku 2000”. Dla nieznających pojęcia chodziło o pewne odmiany BIOSów, które liczyły lata za pomocą dwóch cyfr i przy przejściu w nowe stulecie mogły by pokazywać rok 1900. Oczywiście sprawa okazała się znacznie mniej poważna, a biorąc pod uwagę premierę nowego Windowsa (ME) wielce podejrzana. Mój stary komputer też uległ „awarii” po prostu poprosił przy starcie o wprowadzenie nowej daty systemowej, którą zaszył w BIOSie jako punkt startu zegara. Dziś spotkałem się z innym rozwiązaniem stosowanym na starych mainframach. Data (dzień) są podawane jako liczba dni od 1 stycznia 1900 roku. Piękne. Tylko, że trzeba by daty tłumaczyć na coś co można obsłużyć w javie. W dodatku taki format daty obowiązuje w bazie danych (pole jako numeric).

Przeliczanie daty na stary format nie jest problemem, gorzej wygląda przeliczanie starego formatu na coś co można podać klasie GregorianCalendar. Na chwilę obecną wykombinowałem takie coś… jutro będzie się testować 🙂

Listing 1. Kocham moje MCP

package eu.runelord.blog.datecalculator;

import java.util.GregorianCalendar;

public class Calculator {

	private static final GregorianCalendar CALENDAR = new GregorianCalendar(
			1900, 1, 1);

	public static void main(String[] args) {
		GregorianCalendar now = new GregorianCalendar(1900, 0, 1);

		long dayNumber = dayToNumber(now);
		System.out.println(dayNumber);
		GregorianCalendar now2 = numberToDay(dayNumber);
		System.out.println(now2.get(GregorianCalendar.YEAR) + ","
				+ now2.get(GregorianCalendar.MONTH) + ","
				+ now2.get(GregorianCalendar.DAY_OF_MONTH));
	}

	private static GregorianCalendar numberToDay(long now) {
		int year = (int) (now / 365.25);
		int month = (int) ((now + 1 - (year * 365.25)) / 30.4375);
		int day = (int) (1 + (now + 1 - (year * 365.25)) / 12);
		GregorianCalendar ret = new GregorianCalendar(year + 1900, month, day);
		return ret;
	}

	private static long dayToNumber(GregorianCalendar now) {
		long years = 1 + (long) (365.25 * (now.get(GregorianCalendar.YEAR) - CALENDAR
				.get(GregorianCalendar.YEAR)));

		long days = now.get(GregorianCalendar.DAY_OF_YEAR) - 1;

		return years + days;
	}
}

//edit

oczywiście druga metoda nie bangla…
Bardzo krótka wersja, która działa:

Listing 2. Kocham MCP, naprawdę

	public static GregorianCalendar elixirToDate(Long elixir) {
		Date date = new Date((elixir - _1170) * 86400000);
		GregorianCalendar ret = new GregorianCalendar(date.getYear() + 1900,
				date.getMonth(), date.getDate());
		return ret;
	}