<commit_before>/*
 * Copyright (C) 2009 JavaRosa
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.javarosa.core.model.utils;

import java.util.Calendar;
import java.util.Date;
import java.util.Vector;

import org.javarosa.core.services.locale.Localization;
import org.javarosa.core.util.MathUtils;

/**
 * Static utility methods for Dates in j2me 
 * 
 * @author <NAME>
 *
 */

public class DateUtils {
	private static final int MONTH_OFFSET = (1 - Calendar.JANUARY);
		
	public static final int FORMAT_ISO8601 = 1;
	public static final int FORMAT_HUMAN_READABLE_SHORT = 2;
	public static final int FORMAT_HUMAN_READABLE_DAYS_FROM_TODAY = 5;
	//public static final int FORMAT_HUMAN_READABLE_LONG = 3;
	public static final int FORMAT_TIMESTAMP_SUFFIX = 7;
	
	public static final long DAY_IN_MS = 86400000l;
	
	public DateUtils() {
		super();
	}

	public static class DateFields {
		public DateFields () {
			year = 1970;
			month = 1;
			day = 1;
			hour = 0;
			minute = 0;
			second = 0;
			secTicks = 0;
			
//			tzStr = "Z";
//			tzOffset = 0;
		}
		
		public int year;
		public int month; //1-12
		public int day; //1-31
		public int hour; //0-23
		public int minute; //0-59
		public int second; //0-59
		public int secTicks; //0-999 (ms)
		
//		public String tzStr;
//		public int tzOffset; //s ahead of UTC
		
		public boolean check () {
			return (inRange(month, 1, 12) && inRange(day, 1, daysInMonth(month - MONTH_OFFSET, year)) &&
					inRange(hour, 0, 23) && inRange(minute, 0, 59) && inRange(second, 0, 59) && inRange(secTicks, 0, 999));
		}
	}
	
	public static DateFields getFields (Date d) {
		Calendar cd = Calendar.getInstance();
		cd.setTime(d);
		
		DateFields fields = new DateFields();
		fields.year = cd.get(Calendar.YEAR);
		fields.month = cd.get(Calendar.MONTH) + MONTH_OFFSET;
		fields.day = cd.get(Calendar.DAY_OF_MONTH);
		fields.hour = cd.get(Calendar.HOUR_OF_DAY);
		fields.minute = cd.get(Calendar.MINUTE);
		fields.second = cd.get(Calendar.SECOND);
		fields.secTicks = cd.get(Calendar.MILLISECOND);
		
		return fields;
	}
	
	public static Date getDate (DateFields f) {
		Calendar cd = Calendar.getInstance();
		cd.set(Calendar.YEAR, f.year);
		cd.set(Calendar.MONTH, f.month - MONTH_OFFSET);
		cd.set(Calendar.DAY_OF_MONTH, f.day);
		cd.set(Calendar.HOUR_OF_DAY, f.hour);
		cd.set(Calendar.MINUTE, f.minute);
		cd.set(Calendar.SECOND, f.second);
		cd.set(Calendar.MILLISECOND, f.secTicks);
		
		return cd.getTime();		
	}
	
	/* ==== FORMATTING DATES/TIMES TO STANDARD STRINGS ==== */
	
	public static String formatDateTime (Date d, int format) {
		if (d == null)
			return "";
		
		DateFields fields = getFields(d);

		String delim;
		switch (format) {
		case FORMAT_ISO8601: delim = "T"; break;
		case FORMAT_TIMESTAMP_SUFFIX: delim = ""; break;
		default: delim = " "; break;
		}
		
		return formatDate(fields, format) + delim + formatTime(fields, format);
	}
	
	public static String formatDate (Date d, int format) {
		return (d == null ? "" :formatDate(getFields(d), format));
	}
	
	public static String formatTime (Date d, int format) {
		return (d == null ? "" : formatTime(getFields(d), format));
	}
	
	private static String formatDate (DateFields f, int format) {
		switch (format) {
		case FORMAT_ISO8601: return formatDateISO8601(f);
		case FORMAT_HUMAN_READABLE_SHORT: return formatDateColloquial(f);
		case FORMAT_HUMAN_READABLE_DAYS_FROM_TODAY: return formatDaysFromToday(f);
		case FORMAT_TIMESTAMP_SUFFIX: return formatDateSuffix(f);
		default: return null;
		}	
	}
	
	private static String formatTime (DateFields f, int format) {
		switch (format) {
		case FORMAT_ISO8601: return formatTimeISO8601(f);
		case FORMAT_HUMAN_READABLE_SHORT: return formatTimeColloquial(f);
		case FORMAT_TIMESTAMP_SUFFIX: return formatTimeSuffix(f);
		default: return null;
		}	
	}
	
	private static String formatDateISO8601 (DateFields f) {
		return f.year + "-" + intPad(f.month, 2) + "-" + intPad(f.day, 2);
	}

	private static String formatDateColloquial (DateFields f) {
		return intPad(f.day, 2) + "/" + intPad(f.month, 2) + "/" + (new Integer(f.year)).toString().substring(2, 4);
	}

	private static String formatDateSuffix (DateFields f) {
		return f.year + intPad(f.month, 2) + intPad(f.day, 2);
	}
	
	private static String formatTimeISO8601 (DateFields f) {
		return intPad(f.hour, 2) + ":" + intPad(f.minute, 2) + ":" + intPad(f.second, 2) + "." + intPad(f.secTicks, 3);
		//want to add time zone info to be fully ISO-8601 compliant, but API is totally on crack!
	}
	
	private static String formatTimeColloquial (DateFields f) {
		return intPad(f.hour, 2) + ":" + intPad(f.minute, 2);
	}

	private static String formatTimeSuffix (DateFields f) {
		return intPad(f.hour, 2) + intPad(f.minute, 2) + intPad(f.second, 2);
	}
	
	/* ==== PARSING DATES/TIMES FROM STANDARD STRINGS ==== */
	
	public static Date parseDateTime (String str) {
		DateFields fields = new DateFields();
		int i = str.indexOf("T");
		if (i != -1) {<commit_msg>Resolved Bug 11146: Ancient dates cause exception.<commit_after>/*
 * Copyright (C) 2009 JavaRosa
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.javarosa.core.model.utils;

import java.util.Calendar;
import java.util.Date;
import java.util.Vector;

import org.javarosa.core.services.locale.Localization;
import org.javarosa.core.util.MathUtils;

/**
 * Static utility methods for Dates in j2me 
 * 
 * @author <NAME>
 *
 */

public class DateUtils {
	private static final int MONTH_OFFSET = (1 - Calendar.JANUARY);
		
	public static final int FORMAT_ISO8601 = 1;
	public static final int FORMAT_HUMAN_READABLE_SHORT = 2;
	public static final int FORMAT_HUMAN_READABLE_DAYS_FROM_TODAY = 5;
	//public static final int FORMAT_HUMAN_READABLE_LONG = 3;
	public static final int FORMAT_TIMESTAMP_SUFFIX = 7;
	
	public static final long DAY_IN_MS = 86400000l;
	
	public DateUtils() {
		super();
	}

	public static class DateFields {
		public DateFields () {
			year = 1970;
			month = 1;
			day = 1;
			hour = 0;
			minute = 0;
			second = 0;
			secTicks = 0;
			
//			tzStr = "Z";
//			tzOffset = 0;
		}
		
		public int year;
		public int month; //1-12
		public int day; //1-31
		public int hour; //0-23
		public int minute; //0-59
		public int second; //0-59
		public int secTicks; //0-999 (ms)
		
//		public String tzStr;
//		public int tzOffset; //s ahead of UTC
		
		public boolean check () {
			return (inRange(month, 1, 12) && inRange(day, 1, daysInMonth(month - MONTH_OFFSET, year)) &&
					inRange(hour, 0, 23) && inRange(minute, 0, 59) && inRange(second, 0, 59) && inRange(secTicks, 0, 999));
		}
	}
	
	public static DateFields getFields (Date d) {
		Calendar cd = Calendar.getInstance();
		cd.setTime(d);
		
		DateFields fields = new DateFields();
		fields.year = cd.get(Calendar.YEAR);
		fields.month = cd.get(Calendar.MONTH) + MONTH_OFFSET;
		fields.day = cd.get(Calendar.DAY_OF_MONTH);
		fields.hour = cd.get(Calendar.HOUR_OF_DAY);
		fields.minute = cd.get(Calendar.MINUTE);
		fields.second = cd.get(Calendar.SECOND);
		fields.secTicks = cd.get(Calendar.MILLISECOND);
		
		return fields;
	}
	
	public static Date getDate (DateFields f) {
		Calendar cd = Calendar.getInstance();
		cd.set(Calendar.YEAR, f.year);
		cd.set(Calendar.MONTH, f.month - MONTH_OFFSET);
		cd.set(Calendar.DAY_OF_MONTH, f.day);
		cd.set(Calendar.HOUR_OF_DAY, f.hour);
		cd.set(Calendar.MINUTE, f.minute);
		cd.set(Calendar.SECOND, f.second);
		cd.set(Calendar.MILLISECOND, f.secTicks);
		
		return cd.getTime();		
	}
	
	/* ==== FORMATTING DATES/TIMES TO STANDARD STRINGS ==== */
	
	public static String formatDateTime (Date d, int format) {
		if (d == null)
			return "";
		
		DateFields fields = getFields(d);

		String delim;
		switch (format) {
		case FORMAT_ISO8601: delim = "T"; break;
		case FORMAT_TIMESTAMP_SUFFIX: delim = ""; break;
		default: delim = " "; break;
		}
		
		return formatDate(fields, format) + delim + formatTime(fields, format);
	}
	
	public static String formatDate (Date d, int format) {
		return (d == null ? "" :formatDate(getFields(d), format));
	}
	
	public static String formatTime (Date d, int format) {
		return (d == null ? "" : formatTime(getFields(d), format));
	}
	
	private static String formatDate (DateFields f, int format) {
		switch (format) {
		case FORMAT_ISO8601: return formatDateISO8601(f);
		case FORMAT_HUMAN_READABLE_SHORT: return formatDateColloquial(f);
		case FORMAT_HUMAN_READABLE_DAYS_FROM_TODAY: return formatDaysFromToday(f);
		case FORMAT_TIMESTAMP_SUFFIX: return formatDateSuffix(f);
		default: return null;
		}	
	}
	
	private static String formatTime (DateFields f, int format) {
		switch (format) {
		case FORMAT_ISO8601: return formatTimeISO8601(f);
		case FORMAT_HUMAN_READABLE_SHORT: return formatTimeColloquial(f);
		case FORMAT_TIMESTAMP_SUFFIX: return formatTimeSuffix(f);
		default: return null;
		}	
	}
	
	private static String formatDateISO8601 (DateFields f) {
		return f.year + "-" + intPad(f.month, 2) + "-" + intPad(f.day, 2);
	}

	private static String formatDateColloquial (DateFields f) {
		String year = new Integer(f.year).toString();
		
		//Normal Date
		if(year.length() == 4) {
			year = year.substring(2, 4);
		}
		//Otherwise we have an old or bizzarre date, don't try to do anything
		
		return intPad(f.day, 2) + "/" + intPad(f.month, 2) + "/" + year;
	}

	private static String formatDateSuffix (DateFields f) {
		return f.year + intPad(f.month, 2) + intPad(f.day, 2);
	}
	
	private static String formatTimeISO8601 (DateFields f) {
		return intPad(f.hour, 2) + ":" + intPad(f.minute, 2) + ":" + intPad(f.second, 2) + "." + intPad(f.secTicks, 3);
		//want to add time zone info to be fully ISO-8601 compliant, but API is totally on crack!
	}
	
	private static String formatTimeColloquial (DateFields f) {
		return intPad(f.hour, 2) + ":" + intPad(f.minute, 2);
	}

	private static String formatTimeSuffix (DateFields f) {
		return intPad(f.hour, 2) + intPad(f.minute, 2) + intPad(f.second, 2);
	}
	
	/* ==== PARSING DATES/TIMES FROM STANDARD STRINGS ==== */
	
	public static Date parseDateTime (String str) {
		DateFields fields = new DateFields();
		int i = str.indexOf("T");
		if (i != -1) {
{'fraction_non_alphanumeric': 0.12470904207699195, 'fraction_numerical': 0.022739480752014325, 'mean_word_length': 3.735481136074608, 'pattern_counts': {'":': 6, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6124359', 'n_tokens_mistral': 4374, 'n_tokens_neox': 3822, 'n_words': 1094}