My answer to intraday segmentedtimeline problems

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
clam61
Posts: 66
Joined: Tue Jul 03, 2007 9:59 pm

My answer to intraday segmentedtimeline problems

Post by clam61 » Tue Jul 31, 2007 12:42 am

i created a new class which i hope will be an option to segmented timeline.

below is my code. i believe this is a good start. it almost works. i cant seem to figure out whats wrong with it. the code seems simple. please try it out on your charts.

here is the signature for the constructor. this is all you need

Code: Select all

    public IntradayMarketTimeline(long sundayStart, long sundayEnd,
	                          long mondayStart, long mondayEnd,
	                          long tuesdayStart, long tuesdayEnd,
	                          long wednesdayStart, long wednesdayEnd,
	                          long thursdayStart, long thursdayEnd,
	                          long fridayStart, long fridayEnd,
	                          long saturdayStart, long saturdayEnd) 
i did not implement holidays yet, but basically all you do is specify the start and stop times for each day. Here is some sample code to specify a monday through friday timeline, starting at 9:30am and ending at 4:00pm

Code: Select all

IntradayMarketTimeline testedObject = new IntradayMarketTimeline(
	    0L,
	    0L,
	    34200000L,
	    57600000L,
	    34200000L,
	    57600000L,
	    34200000L,
	    57600000L,
	    34200000L,
	    57600000L,
	    34200000L,
	    57600000L,
	    0L,
	    0L);    


the values for the start and stop times are the number of milliseconds from 00:00 for that day. so in these examples, saturday and sunday have start and stop times of 0 and 0 because we dont want activities on these days.

the rest of the days start at 9:30 am and stop at 4:00pm. 9:30 am is 9.5 hours * 60 min * 60 sec * 1000 millisec = 34200000 milliseconds from 00:00 for that day

likewise 4:00pm is 16 hours * 60 min .... = 57600000 milliseconds from 00:00 for that day

below is the code. i think my algorithm is simple. some of my comments might be lacking. feel free to ask questions.

Code: Select all

import org.jfree.chart.axis.Timeline;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.Calendar;
import java.util.ArrayList;

/**
 *
 */
public class IntradayMarketTimeline implements Timeline {
    private long sundayStart = 0;
    private long sundayEnd = 0;
    private long mondayStart = 0;
    private long mondayEnd = 0;
    private long tuesdayStart = 0;
    private long tuesdayEnd = 0;
    private long wednesdayStart = 0;
    private long wednesdayEnd = 0;
    private long thursdayStart = 0;
    private long thursdayEnd = 0;
    private long fridayStart = 0;
    private long fridayEnd = 0;
    private long saturdayStart = 0;
    private long saturdayEnd = 0;
    private long sundayActive = 0;
    private long mondayActive = 0;
    private long tuesdayActive = 0;
    private long wednesdayActive = 0;
    private long thursdayActive = 0;
    private long fridayActive = 0;
    private long saturdayActive = 0;

    private long activeTimePerWeek = 0;
    //private long closedTimePerWeek = 0;
    
    private static final long MILLIS_PER_WEEK = 7 * 24 * 60 * 60 * 1000;
    private static final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;

    //specify the start and end times for the market
    //times are given in milliseconds in relation to 00:00 for that day.
    //so a start time of 01:00 would be 1 hour * 60 minutes * 60 seconds * 1000 milliseconds
    public IntradayMarketTimeline(long sundayStart, long sundayEnd,
	                          long mondayStart, long mondayEnd,
	                          long tuesdayStart, long tuesdayEnd,
	                          long wednesdayStart, long wednesdayEnd,
	                          long thursdayStart, long thursdayEnd,
	                          long fridayStart, long fridayEnd,
	                          long saturdayStart, long saturdayEnd) {
	this.sundayStart = sundayStart;
	this.sundayEnd = sundayEnd;
	this.mondayStart = mondayStart;
	this.mondayEnd = mondayEnd;
	this.tuesdayStart = tuesdayStart;
	this.tuesdayEnd = tuesdayEnd;
	this.wednesdayStart = wednesdayStart;
	this.wednesdayEnd = wednesdayEnd;
	this.thursdayStart = thursdayStart;
	this.thursdayEnd = thursdayEnd;
        this.fridayStart = fridayStart;
        this.fridayEnd = fridayEnd;
        this.saturdayStart = saturdayStart;
        this.saturdayEnd = saturdayEnd;
        
        //calculate the amount of time the market is open during each day
        this.sundayActive = this.sundayEnd - this.sundayStart;
        this.mondayActive = this.mondayEnd - this.mondayStart;
        this.tuesdayActive = this.tuesdayEnd - this.tuesdayStart;
        this.wednesdayActive = this.wednesdayEnd - this.wednesdayStart;
        this.thursdayActive = this.thursdayEnd - this.thursdayStart;
        this.fridayActive = this.fridayEnd - this.fridayStart;
        this.saturdayActive = this.saturdayEnd - this.saturdayStart;
        
        this.activeTimePerWeek = this.sundayActive + 
                                 this.mondayActive + this.tuesdayActive + 
                                 this.wednesdayActive + this.thursdayActive + 
                                 this.fridayActive + this.saturdayActive;
        
        //calculate the amount of time the market is closed each week
        //this.closedTimePerWeek = this.MILLIS_PER_WEEK - this.activeTimePerWeek;
    }
    
    /**
     * Translates a millisecond (as defined by java.util.Date) into an index 
     * along this timeline.
     *
     * @param target - the milliseconds of a date to convert
     * 
     * @return A timeline value.
     */
    public long toTimelineValue(long currentDayMillis) {
	
	//
	//find out the day of the week the current day is
	//SUNDAY = 1,...SATURDAY = 7
	Calendar currentDay = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
	currentDay.setTimeInMillis(currentDayMillis);

	//a list of the days from the current date until last thursday 00:00
	//which includes thursday itself from (00:00,23:59)
	ArrayList<Integer> daysFromThursday = new ArrayList();
	
	Calendar lastThursday = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

	lastThursday.setTimeInMillis(currentDayMillis);
	
	//move backwards in time until you hit a wednesday
	while (lastThursday.get(Calendar.DAY_OF_WEEK) != Calendar.THURSDAY) {
	    //add this day to the list
	    daysFromThursday.add(new Integer(lastThursday.get(Calendar.DAY_OF_WEEK)));
	    //
	    //move back one more day
            lastThursday.add(Calendar.DATE, -1);
        }
	    //
	//add thursday to the list
        daysFromThursday.add(new Integer(Calendar.THURSDAY));
	    
	  
	//adjust Calendar to the beginning of last thursday
	lastThursday.set(Calendar.MILLISECOND, 0);
	lastThursday.set(Calendar.SECOND, 0);
	lastThursday.set(Calendar.MINUTE, 0);
        lastThursday.set(Calendar.HOUR_OF_DAY, 0);
        
	//get the milliseconds for the beginning of last Thursday
	long lastThursdayMillis = lastThursday.getTimeInMillis();
	
	//because Jan 1, 1970 was a Thursday, lastThursdayMillis 
	//gives an even # of weeks from Jan 1, 1970 until lastThursdayMillis.  
	//so subtract the (down time per week * the 
	//number of weeks) since Jan 1, 1970
	
	//the number of weeks since Jan 1, 1970
	int numberOfWeeks = (int) Math.round((new Long(lastThursdayMillis/this.MILLIS_PER_WEEK)).doubleValue());
	TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
	
	TimeZone.setDefault(TimeZone.getDefault());
	
	//get the timeline value for the number of millis since 
	//Jan 1, 1970 to last thursday, by multiplying the number of weeks
	//since Jan 1, 1970 by the amount of active milliseconds per week
	long timelineValue = numberOfWeeks * this.activeTimePerWeek;
//	        
	//add the amount of active millseconds for the current day
	//of the given time
	long millisOfCurrentDay = currentDay.get(Calendar.HOUR_OF_DAY) * 3600000 + 
                                  currentDay.get(Calendar.MINUTE) * 60000 + 
	                          currentDay.get(Calendar.SECOND) * 1000 + 
	                          currentDay.get(Calendar.MILLISECOND);

	long startOfCurrentDay = this.getStartTime(currentDay.get(Calendar.DAY_OF_WEEK));
	long endOfCurrentDay = this.getEndTime(currentDay.get(Calendar.DAY_OF_WEEK));

                    Integer.toString(currentDay.get(Calendar.MINUTE)) + " " +
	                          Integer.toString(currentDay.get(Calendar.SECOND))+":"+
	                          Integer.toString(currentDay.get(Calendar.MILLISECOND)));
	
	
	
	if (millisOfCurrentDay >= startOfCurrentDay && millisOfCurrentDay <= endOfCurrentDay) {
	    
	    timelineValue += millisOfCurrentDay - startOfCurrentDay;
	}
	
	//get the size of the list
	int listSize = daysFromThursday.size();

        //add the active time since last thursday, skipping the first day since
	//we already took care of that
	for (int i = 1; i < listSize; i++) {
	    int day = ((Integer) daysFromThursday.get(i)).intValue();
	    
	    timelineValue += this.getActiveTimePerDay(day);
    
	}
	

        return timelineValue;
    }

    /**
     * Translates a date into a value on this timeline.
     *
     * @param date  the date.
     * 
     * @return A timeline value
     */
    public long toTimelineValue(Date date) {
        //normalize to GMT
	return this.toTimelineValue(date.getTimezoneOffset() + date.getTime());
    }

    /**
     * Translates a value relative to this timeline into a domain value. The 
     * domain value obtained by this method is not always the same domain value 
     * that could have been supplied to 
     * translateDomainValueToTimelineValue(domainValue).
     * This is because the original tranformation may not be complete 
     * reversable.
     *
     * @see org.jfree.chart.axis.SegmentedTimeline
     *
     * @param timelineValue  a timeline value.
     * 
     * @return A domain value.
     */
    public long toMillisecond(long timelineValue) {
	
	
	
	if (this.activeTimePerWeek == 0L)
	    return 0;
	
	//starting from Jan 1, 1970 work backwards.
	//find out the number of whole weeks in the timelineValue
	Long l = new Long(timelineValue/this.activeTimePerWeek);
	int numWeeks = (int) Math.floor(l.doubleValue());
	
	//the amount of time left on the timeline from the last thursday
	long timeLeftSinceThursday = timelineValue - (numWeeks * this.activeTimePerWeek);
	
	int day = Calendar.THURSDAY;
	int numDays = 0;
	
	//from last friday until the current day
	//if the amount of time left is greater than
	//the active time for that day, increment the number of
	//days and subtract from the time left
	while (numDays < 7) {
	    if (day == Calendar.SUNDAY) {
		if (timeLeftSinceThursday > this.sundayActive) {
		    timeLeftSinceThursday -= this.sundayActive;
                    numDays++;
		}
		else {
		    break;
		}
	    }
	    else if (day == Calendar.MONDAY) {
		if (timeLeftSinceThursday > this.mondayActive) {
		    timeLeftSinceThursday -= this.mondayActive;
                    numDays++;
		}
		else {
		    break;
		}
	    }	
	    else if (day == Calendar.TUESDAY) {
		if (timeLeftSinceThursday > this.tuesdayActive) {
		    timeLeftSinceThursday -= this.tuesdayActive;
                    numDays++;
		}
		else {
		    break;
		}
	    }	
	    else if (day == Calendar.WEDNESDAY) {
		if (timeLeftSinceThursday > this.wednesdayActive) {
		    timeLeftSinceThursday -= this.wednesdayActive;
                    numDays++;
		}
		else {
		    break;
		}
	    }	
	    else if (day == Calendar.THURSDAY) {

		if (timeLeftSinceThursday > this.thursdayActive) {
		    timeLeftSinceThursday -= this.thursdayActive;
                    numDays++;
                    
                    //thursday numDays =  " + Integer.toString(numDays));
		}
		else {
		                        
		    break;
		}
	    }	
	    else if (day == Calendar.FRIDAY) {
		if (timeLeftSinceThursday > this.fridayActive) {
		    timeLeftSinceThursday -= this.fridayActive;
                    numDays++;
		}
		else {
		    break;
		}
	    }	
	    else if (day == Calendar.SATURDAY) {
		if (timeLeftSinceThursday > this.saturdayActive) {
		    timeLeftSinceThursday -= this.saturdayActive;
                    numDays++;
		}
		else {
		    break;
		}
	    }	
	    
            day = this.nextDay(day);
	}
	
	
	long millis = numWeeks * this.MILLIS_PER_WEEK + 
	              numDays * this.MILLIS_PER_DAY +
	              this.getStartTime(day) + timeLeftSinceThursday;
	    
	
	
	return millis;
    }

    /**
     * Returns <code>true</code> if a value is contained in the timeline values.
     *
     * @param millisecond  the millisecond.
     * 
     * @return <code>true</code> if value is contained in the timeline and 
     *         <code>false</code> otherwise.
     */
    public boolean containsDomainValue(long millisecond) {
	Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
	cal.setTimeInMillis(millisecond);
	
	return isActiveDate(cal);
    }

    /**
     * Returns <code>true</code> if a date is contained in the timeline values.
     *
     * @param date  the date to verify.
     * 
     * @return <code>true</code> if value is contained in the timeline and 
     *         <code>false</code>  otherwise.
     */
    public boolean containsDomainValue(Date date) {
        //normalize to GMT
	return this.containsDomainValue(date.getTimezoneOffset() + date.getTime());
    }

    /**
     * Returns <code>true</code> if a range of values are contained in the 
     * timeline.
     *
     * @param fromMillisecond  the start of the range to verify.
     * @param toMillisecond  the end of the range to verify.
     * 
     * @return <code>true</code> if the range is contained in the timeline or 
     *         <code>false</code> otherwise
     */
    public boolean containsDomainRange(long fromMillisecond, long toMillisecond) {
	Calendar cal1 = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
	Calendar cal2 = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
	
	cal1.setTimeInMillis(fromMillisecond);
	cal2.setTimeInMillis(toMillisecond);
	
	return this.isActiveDate(cal1, cal2);
    }

    /**
     * Returns <code>true</code> if a range of dates are contained in the 
     * timeline.
     *
     * @param fromDate  the start of the range to verify.
     * @param toDate  the end of the range to verify.
     * 
     * @return <code>true</code> if the range is contained in the timeline or 
     *         <code>false</code> otherwise
     */
    public boolean containsDomainRange(Date fromDate, Date toDate) {
        //normalize to GMT
	return this.containsDomainRange(fromDate.getTimezoneOffset() + fromDate.getTime(), toDate.getTimezoneOffset() + toDate.getTime());
    }

    private long getActiveTimePerDay(int day) {
	long closedTime = 0;
	
	    if (day == Calendar.SUNDAY) {
		closedTime = this.sundayActive;
	    }
	    else if (day == Calendar.MONDAY) {
		closedTime = this.mondayActive;		
	    }
	    else if (day == Calendar.TUESDAY) {
		closedTime = this.tuesdayActive;
	    }
	    else if (day == Calendar.WEDNESDAY) {
		closedTime = this.wednesdayActive;
	    }
	    else if (day == Calendar.THURSDAY) {
		closedTime = this.thursdayActive;
	    }
	    else if (day == Calendar.FRIDAY) {
		closedTime = this.fridayActive;
	    }
	    else if (day == Calendar.SATURDAY) {
		closedTime = this.saturdayActive;
	    }
	    
	    return closedTime;
    }
    
    private long getStartTime(int day) {
	long startTime = 0;
	
        if (day == Calendar.SUNDAY) {
	    startTime = this.sundayStart;
	}
	else if (day == Calendar.MONDAY) {
	    startTime = this.mondayStart;
	}
	else if (day == Calendar.TUESDAY) {
	    startTime = this.tuesdayStart;
	}
	else if (day == Calendar.WEDNESDAY) {
	    startTime = this.wednesdayStart;
	}
	else if (day == Calendar.THURSDAY) {
	    startTime = this.thursdayStart;
	}
	else if (day == Calendar.FRIDAY) {
	    startTime = this.fridayStart;
	}
	else if (day == Calendar.SATURDAY) {
	    startTime = this.saturdayStart;
	}
        
        return startTime;
    }

    private long getEndTime(int day) {
	long endTime = 0;
	
        if (day == Calendar.SUNDAY) {
	    endTime = this.sundayEnd;
	}
	else if (day == Calendar.MONDAY) {
	    endTime = this.mondayEnd;
	}
	else if (day == Calendar.TUESDAY) {
	    endTime = this.tuesdayEnd;
	}
	else if (day == Calendar.WEDNESDAY) {
	    endTime = this.wednesdayEnd;
	}
	else if (day == Calendar.THURSDAY) {
	    endTime = this.thursdayEnd;
	}
	else if (day == Calendar.FRIDAY) {
	    endTime = this.fridayEnd;
	}
	else if (day == Calendar.SATURDAY) {
	    endTime = this.saturdayEnd;
	}
        
        return endTime;
    }
    
    private boolean isActiveDate(Calendar cal) {
	int day = cal.get(Calendar.DAY_OF_WEEK);
	
	long timeSinceStart = cal.get(Calendar.HOUR_OF_DAY) * 3600000 + 
                              cal.get(Calendar.MINUTE) * 60000 + 
	                      cal.get(Calendar.SECOND) * 1000;
	
        if (day == Calendar.SUNDAY) {
	    return (timeSinceStart > this.sundayStart && timeSinceStart < this.sundayEnd);
	}
	else if (day == Calendar.MONDAY) {
	    return (timeSinceStart > this.mondayStart && timeSinceStart < this.mondayEnd);
	}
	else if (day == Calendar.TUESDAY) {
	    return (timeSinceStart > this.tuesdayStart && timeSinceStart < this.tuesdayEnd);
	}
	else if (day == Calendar.WEDNESDAY) {
	    return (timeSinceStart > this.wednesdayStart && timeSinceStart < this.wednesdayEnd);
	}
	else if (day == Calendar.THURSDAY) {
	    return (timeSinceStart > this.thursdayStart && timeSinceStart < this.thursdayEnd);
	}
	else if (day == Calendar.FRIDAY) {
	    return (timeSinceStart > this.fridayStart && timeSinceStart < this.fridayEnd);
	}
	else if (day == Calendar.SATURDAY) {
	    return (timeSinceStart > this.saturdayStart && timeSinceStart < this.saturdayEnd);
	}
	else {
	    return false;
	}
    }
    
    private boolean isActiveDate(Calendar cal, Calendar cal2) {
        int day = cal.get(Calendar.DAY_OF_WEEK);

	long timeSinceStart = cal.get(Calendar.HOUR_OF_DAY) * 3600000 + 
                              cal.get(Calendar.MINUTE) * 60000 + 
	                      cal.get(Calendar.SECOND) * 1000;
	
	boolean firstDate = false;
	
        if (day == Calendar.SUNDAY) {
	    firstDate = (timeSinceStart > this.sundayStart && timeSinceStart < this.sundayEnd);
	}
	else if (day == Calendar.MONDAY) {
	    firstDate = (timeSinceStart > this.mondayStart && timeSinceStart < this.mondayEnd);
	}
	else if (day == Calendar.TUESDAY) {
	    firstDate = (timeSinceStart > this.tuesdayStart && timeSinceStart < this.tuesdayEnd);
	}
	else if (day == Calendar.WEDNESDAY) {
	    firstDate = (timeSinceStart > this.wednesdayStart && timeSinceStart < this.wednesdayEnd);
	}
	else if (day == Calendar.THURSDAY) {
	    firstDate = (timeSinceStart > this.thursdayStart && timeSinceStart < this.thursdayEnd);
	}
	else if (day == Calendar.FRIDAY) {
	    firstDate = (timeSinceStart > this.fridayStart && timeSinceStart < this.fridayEnd);
	}
	else if (day == Calendar.SATURDAY) {
	    firstDate = (timeSinceStart > this.saturdayStart && timeSinceStart < this.saturdayEnd);
	}
	else {
	    firstDate = false;
	}
        
        int day2 = cal2.get(Calendar.DAY_OF_WEEK);
        
	timeSinceStart = cal2.get(Calendar.HOUR_OF_DAY) * 3600000 + 
                              cal2.get(Calendar.MINUTE) * 60000 + 
	                      cal2.get(Calendar.SECOND) * 1000;
	
	boolean secondDate = false;
	
        if (day2 == Calendar.SUNDAY) {
	    secondDate = (timeSinceStart > this.sundayStart && timeSinceStart < this.sundayEnd);
	}
	else if (day2 == Calendar.MONDAY) {
	    secondDate = (timeSinceStart > this.mondayStart && timeSinceStart < this.mondayEnd);
	}
	else if (day2 == Calendar.TUESDAY) {
	    secondDate = (timeSinceStart > this.tuesdayStart && timeSinceStart < this.tuesdayEnd);
	}
	else if (day2 == Calendar.WEDNESDAY) {
	    secondDate = (timeSinceStart > this.wednesdayStart && timeSinceStart < this.wednesdayEnd);
	}
	else if (day2 == Calendar.THURSDAY) {
	    secondDate = (timeSinceStart > this.thursdayStart && timeSinceStart < this.thursdayEnd);
	}
	else if (day2 == Calendar.FRIDAY) {
	    secondDate = (timeSinceStart > this.fridayStart && timeSinceStart < this.fridayEnd);
	}
	else if (day2 == Calendar.SATURDAY) {
	    secondDate = (timeSinceStart > this.saturdayStart && timeSinceStart < this.saturdayEnd);
	}
	else {
	    secondDate = false;
	}
        
        return (firstDate && secondDate);
    }
    
    private int nextDay(int day) {
	day++;
	
	day = day % 7;
	
	return day;
    }
    
    public static void main(String[] args) {
	TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
	IntradayMarketTimeline testedObject = new IntradayMarketTimeline(
	    0L,
	    0L,
	    34200000L,
	    57600000L,
	    34200000L,
	    57600000L,
	    34200000L,
	    57600000L,
	    34200000L,
	    57600000L,
	    34200000L,
	    57600000L,
	    0L,
	    0L);

	//one week + 1 day  +  10:48am
	//604800000
	//86400000
	System.out.println("millisecond -> timeline" +Long.toString(
		IntradayMarketTimeline.MILLIS_PER_DAY + 
		IntradayMarketTimeline.MILLIS_PER_WEEK + 
		+ 38880000L));
		
	//leads to 121680000 milliseconds in timeline time
	System.out.println(Long.toString(testedObject.toTimelineValue(
		IntradayMarketTimeline.MILLIS_PER_DAY + 
		IntradayMarketTimeline.MILLIS_PER_WEEK + 
		+ 38880000L)));
	
	System.out.println("timeline -> millisecond "+Long.toString(testedObject.toMillisecond(145080000L)));
    }
}

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Post by david.gilbert » Tue Jul 31, 2007 10:31 am

Thanks for posting this.

The segmented date axis code is pretty complex and I wonder whether a completely new approach might be worth trying. My own idea (which I haven't had the time to try out) is an axis that maintains a (dynamic, depending on the axis range) tree structure of RegularTimePeriod objects (to distinguish included and excluded periods)...it would need to support at least two levels (e.g. days and hours within days). This might end up being heavy on memory use though, for axes showing a long period of time. I won't know if this will work out until I try it...
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

jwenting
Posts: 157
Joined: Sat Jul 15, 2006 7:46 am

Post by jwenting » Tue Jul 31, 2007 12:32 pm

Maybe maintain only a list of excluded segments.
That would reduce the memory overhead for most cases (usually people will want to exclude vacations or weekends, not have an axis that runs over a long period but only shows one day per month for example).

clam61
Posts: 66
Joined: Tue Jul 03, 2007 9:59 pm

Post by clam61 » Tue Jul 31, 2007 6:44 pm

thanks for the thanks, david!

for me, segmented timeline works on an intraday chart, excluding non market hours, but i have not been able to get it to exclude holidays too. has anyone been able to do this?

btw, for anyone who is looking at my code. the main function is basically just some test code i wrote. i was just lazy and didnt want to write a junit =D

skunk
Posts: 1087
Joined: Thu Jun 02, 2005 10:14 pm
Location: Brisbane, Australia

Post by skunk » Tue Jul 31, 2007 9:57 pm

clam61 wrote:for me, segmented timeline works on an intraday chart, excluding non market hours, but i have not been able to get it to exclude holidays too. has anyone been able to do this?

Code: Select all

timeline.addBaseTimelineException(date);
has always worked for me.

clam61
Posts: 66
Joined: Tue Jul 03, 2007 9:59 pm

Post by clam61 » Tue Jul 31, 2007 10:31 pm

could you please show me a small code snippet? i dont know what i am doing wrong. perhaps it has something to do with timezones?

clam61
Posts: 66
Joined: Tue Jul 03, 2007 9:59 pm

Post by clam61 » Wed Aug 01, 2007 9:13 am

any?

skunk
Posts: 1087
Joined: Thu Jun 02, 2005 10:14 pm
Location: Brisbane, Australia

Post by skunk » Wed Aug 01, 2007 1:57 pm

My guess is that you are missing a call to

Code: Select all

timeline.addBaseTimelineExclusions(...)
after adding all the holidays

develop
Posts: 296
Joined: Wed Mar 23, 2005 10:01 pm

Post by develop » Wed Aug 01, 2007 2:51 pm

i also need sample code. i am not able to skip weekends also for whatever reason. i need to use time for 9:30 to 4.

Please anyone provides sample code would be helpful 8)

clam61
Posts: 66
Joined: Tue Jul 03, 2007 9:59 pm

Post by clam61 » Fri Aug 03, 2007 9:07 am

i have always had addBseTimelineExclusions() in my code. it didnt work

bump

clam61
Posts: 66
Joined: Tue Jul 03, 2007 9:59 pm

Post by clam61 » Tue Aug 07, 2007 7:03 pm

bump

determen77
Posts: 7
Joined: Wed Aug 15, 2007 9:26 pm

Post by determen77 » Wed Aug 29, 2007 4:23 pm

question, is there a purpose to this code fragment:


Integer.toString(currentDay.get(Calendar.MINUTE)) + " " +
Integer.toString(currentDay.get(Calendar.SECOND))+":"+
Integer.toString(currentDay.get(Calendar.MILLISECOND)));

clam61
Posts: 66
Joined: Tue Jul 03, 2007 9:59 pm

Post by clam61 » Wed Aug 29, 2007 4:33 pm

hi, no purpose to that functionally

that is probably an artifact of some code i put in there to debug stuff


determen77 wrote:question, is there a purpose to this code fragment:


Integer.toString(currentDay.get(Calendar.MINUTE)) + " " +
Integer.toString(currentDay.get(Calendar.SECOND))+":"+
Integer.toString(currentDay.get(Calendar.MILLISECOND)));

Carl Manaster
Posts: 35
Joined: Tue Mar 28, 2006 1:10 am
Location: La Jolla
Contact:

Refactored

Post by Carl Manaster » Thu Aug 30, 2007 6:02 pm

Hi,

I refactored the code to cut down on the duplication; I think it's a little easier to follow now. Enjoy.

Peace,
--Carl

Code: Select all

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.TimeZone;

import org.jfree.chart.axis.Timeline;

public class IntradayMarketTimeline implements Timeline {
	private static class Day {
		final long start;
		final long end;
		final long active;
		Day(long start, long end) {
			this.start = start;
			this.end = end;
			active = end - start;
		}
	}

	private final HashMap<Integer, Day> days = new HashMap<Integer, Day>();
	public static final long	MILLIS_PER_WEEK		= 7 * 24 * 60 * 60 * 1000;
	public static final long	MILLIS_PER_DAY		= 24 * 60 * 60 * 1000;
	private long				activeTimePerWeek	= 0;


	// specify the start and end times for the market
	// times are given in milliseconds in relation to 00:00 for that day.
	// so a start time of 01:00 would be 1 hour * 60 minutes * 60 seconds * 1000
	// milliseconds
	public IntradayMarketTimeline(long sundayStart, long sundayEnd, long mondayStart, long mondayEnd, long tuesdayStart, long tuesdayEnd, long wednesdayStart,
			long wednesdayEnd, long thursdayStart, long thursdayEnd, long fridayStart, long fridayEnd, long saturdayStart, long saturdayEnd) {
		days.put(Calendar.SUNDAY, new Day(sundayStart, sundayEnd));
		days.put(Calendar.MONDAY, new Day(mondayStart, mondayEnd));
		days.put(Calendar.TUESDAY, new Day(tuesdayStart, tuesdayEnd));
		days.put(Calendar.WEDNESDAY, new Day(wednesdayStart, wednesdayEnd));
		days.put(Calendar.THURSDAY, new Day(thursdayStart, thursdayEnd));
		days.put(Calendar.FRIDAY, new Day(fridayStart, fridayEnd));
		days.put(Calendar.SATURDAY, new Day(saturdayStart, saturdayEnd));
		
		for (Day day : days.values())
			activeTimePerWeek += day.active;
	}

	/**
	 * Translates a millisecond (as defined by java.util.Date) into an index
	 * along this timeline.
	 * 
	 * @param target -
	 *            the milliseconds of a date to convert
	 * 
	 * @return A timeline value.
	 */
	public long toTimelineValue(long currentDayMillis) {

		//
		// find out the day of the week the current day is
		// SUNDAY = 1,...SATURDAY = 7
		Calendar currentDay = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
		currentDay.setTimeInMillis(currentDayMillis);

		// a list of the days from the current date until last thursday 00:00
		// which includes thursday itself from (00:00,23:59)
		ArrayList<Integer> daysFromThursday = new ArrayList<Integer>();

		Calendar lastThursday = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

		lastThursday.setTimeInMillis(currentDayMillis);

		// move backwards in time until you hit a wednesday
		while (lastThursday.get(Calendar.DAY_OF_WEEK) != Calendar.THURSDAY) {
			// add this day to the list
			daysFromThursday.add(new Integer(lastThursday.get(Calendar.DAY_OF_WEEK)));
			//
			// move back one more day
			lastThursday.add(Calendar.DATE, -1);
		}
		//
		// add thursday to the list
		daysFromThursday.add(new Integer(Calendar.THURSDAY));

		// adjust Calendar to the beginning of last thursday
		lastThursday.set(Calendar.MILLISECOND, 0);
		lastThursday.set(Calendar.SECOND, 0);
		lastThursday.set(Calendar.MINUTE, 0);
		lastThursday.set(Calendar.HOUR_OF_DAY, 0);

		// get the milliseconds for the beginning of last Thursday
		long lastThursdayMillis = lastThursday.getTimeInMillis();

		// because Jan 1, 1970 was a Thursday, lastThursdayMillis
		// gives an even # of weeks from Jan 1, 1970 until lastThursdayMillis.
		// so subtract the (down time per week * the
		// number of weeks) since Jan 1, 1970

		// the number of weeks since Jan 1, 1970
		int numberOfWeeks = (int) Math.round((new Long(lastThursdayMillis / MILLIS_PER_WEEK)).doubleValue());
		TimeZone.setDefault(TimeZone.getTimeZone("GMT"));

		TimeZone.setDefault(TimeZone.getDefault());

		// get the timeline value for the number of millis since
		// Jan 1, 1970 to last thursday, by multiplying the number of weeks
		// since Jan 1, 1970 by the amount of active milliseconds per week
		long timelineValue = numberOfWeeks * activeTimePerWeek;
		//          
		// add the amount of active millseconds for the current day
		// of the given time
		long millisOfCurrentDay = currentDay.get(Calendar.HOUR_OF_DAY) * 3600000 + currentDay.get(Calendar.MINUTE) * 60000 + currentDay.get(Calendar.SECOND)
				* 1000 + currentDay.get(Calendar.MILLISECOND);

		long startOfCurrentDay = getStartTime(currentDay.get(Calendar.DAY_OF_WEEK));
		long endOfCurrentDay = getEndTime(currentDay.get(Calendar.DAY_OF_WEEK));

		if (millisOfCurrentDay >= startOfCurrentDay && millisOfCurrentDay <= endOfCurrentDay) {

			timelineValue += millisOfCurrentDay - startOfCurrentDay;
		}

		// get the size of the list
		int listSize = daysFromThursday.size();

		// add the active time since last thursday, skipping the first day since
		// we already took care of that
		for (int i = 1; i < listSize; i++) {
			int day = daysFromThursday.get(i).intValue();

			timelineValue += getActiveTimePerDay(day);

		}

		return timelineValue;
	}

	/**
	 * Translates a date into a value on this timeline.
	 * 
	 * @param date
	 *            the date.
	 * 
	 * @return A timeline value
	 */
	public long toTimelineValue(Date date) {
		return toTimelineValue(gmtTime(date));
	}

	/**
	 * Translates a value relative to this timeline into a domain value. The
	 * domain value obtained by this method is not always the same domain value
	 * that could have been supplied to
	 * translateDomainValueToTimelineValue(domainValue). This is because the
	 * original tranformation may not be complete reversable.
	 * 
	 * @see org.jfree.chart.axis.SegmentedTimeline
	 * 
	 * @param timelineValue
	 *            a timeline value.
	 * 
	 * @return A domain value.
	 */
	public long toMillisecond(long timelineValue) {

		if (activeTimePerWeek == 0L)
			return 0;

		// starting from Jan 1, 1970 work backwards.
		// find out the number of whole weeks in the timelineValue
		Long l = new Long(timelineValue / activeTimePerWeek);
		int numWeeks = (int) Math.floor(l.doubleValue());

		// the amount of time left on the timeline from the last thursday
		long timeLeftSinceThursday = timelineValue - (numWeeks * activeTimePerWeek);

		int day = Calendar.THURSDAY;
		int numDays = 0;

		// from last friday until the current day
		// if the amount of time left is greater than
		// the active time for that day, increment the number of
		// days and subtract from the time left
		while (numDays < 7) {
			final long timePerDay = getActiveTimePerDay(day);
			if (timeLeftSinceThursday > timePerDay) {
				timeLeftSinceThursday -= timePerDay;
				numDays++;
			} else {
				break;
			}
			day = nextDay(day);
		}

		long millis = numWeeks * MILLIS_PER_WEEK + numDays * MILLIS_PER_DAY + getStartTime(day) + timeLeftSinceThursday;

		return millis;
	}

	/**
	 * Returns <code>true</code> if a value is contained in the timeline
	 * values.
	 * 
	 * @param millisecond
	 *            the millisecond.
	 * 
	 * @return <code>true</code> if value is contained in the timeline and
	 *         <code>false</code> otherwise.
	 */
	public boolean containsDomainValue(long millisecond) {
		Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
		cal.setTimeInMillis(millisecond);

		return isActiveDate(cal);
	}

	/**
	 * Returns <code>true</code> if a date is contained in the timeline
	 * values.
	 * 
	 * @param date
	 *            the date to verify.
	 * 
	 * @return <code>true</code> if value is contained in the timeline and
	 *         <code>false</code> otherwise.
	 */
	@SuppressWarnings("deprecation")
	public boolean containsDomainValue(Date date) {
		return containsDomainValue(gmtTime(date));
	}

	/**
	 * Returns <code>true</code> if a range of values are contained in the
	 * timeline.
	 * 
	 * @param fromMillisecond
	 *            the start of the range to verify.
	 * @param toMillisecond
	 *            the end of the range to verify.
	 * 
	 * @return <code>true</code> if the range is contained in the timeline or
	 *         <code>false</code> otherwise
	 */
	public boolean containsDomainRange(long fromMillisecond, long toMillisecond) {
		Calendar cal1 = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
		Calendar cal2 = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

		cal1.setTimeInMillis(fromMillisecond);
		cal2.setTimeInMillis(toMillisecond);

		return isActiveDate(cal1, cal2);
	}

	/**
	 * Returns <code>true</code> if a range of dates are contained in the
	 * timeline.
	 * 
	 * @param fromDate
	 *            the start of the range to verify.
	 * @param toDate
	 *            the end of the range to verify.
	 * 
	 * @return <code>true</code> if the range is contained in the timeline or
	 *         <code>false</code> otherwise
	 */
	public boolean containsDomainRange(Date fromDate, Date toDate) {
		return containsDomainRange(gmtTime(fromDate), gmtTime(toDate));
	}

	private long getActiveTimePerDay(int day) {
		return days.get(day).active;
	}

	private long getStartTime(int day) {
		return days.get(day).start;
	}

	private long getEndTime(int day) {
		return days.get(day).end;
	}

	private boolean isActiveDate(Calendar cal) {
		int day = cal.get(Calendar.DAY_OF_WEEK);
		long timeSinceStart = cal.get(Calendar.HOUR_OF_DAY) * 3600000 + cal.get(Calendar.MINUTE) * 60000 + cal.get(Calendar.SECOND) * 1000;
		return getStartTime(day) < timeSinceStart && timeSinceStart < getEndTime(day);
	}

	private boolean isActiveDate(Calendar cal, Calendar cal2) {
		return (isActiveDate(cal) && isActiveDate(cal2));
	}

	private int nextDay(int day) {
		day++;

		day = day % 7;

		return day;
	}

	@SuppressWarnings("deprecation")
	private static long gmtTime(Date date) {
		return date.getTimezoneOffset() + date.getTime();
	}

	public static void main(String[] args) {
		TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
		IntradayMarketTimeline testedObject = new IntradayMarketTimeline(0L, 0L, 34200000L, 57600000L, 34200000L, 57600000L, 34200000L, 57600000L, 34200000L,
				57600000L, 34200000L, 57600000L, 0L, 0L);
		
		// one week + 1 day + 10:48am
		// 604800000
		// 86400000
		System.out.println("millisecond -> timeline"
				+ Long.toString(IntradayMarketTimeline.MILLIS_PER_DAY + IntradayMarketTimeline.MILLIS_PER_WEEK + +38880000L));

		// leads to 121680000 milliseconds in timeline time
		System.out.println(Long.toString(testedObject.toTimelineValue(IntradayMarketTimeline.MILLIS_PER_DAY + IntradayMarketTimeline.MILLIS_PER_WEEK
				+ +38880000L)));

		System.out.println("timeline -> millisecond " + Long.toString(testedObject.toMillisecond(145080000L)));
	}
}

clam61
Posts: 66
Joined: Tue Jul 03, 2007 9:59 pm

Post by clam61 » Thu Aug 30, 2007 7:04 pm

awesome...but does it work now?!

did you ever find out the problem with it?

Locked