MonthWeekEventsView.java revision 09b1b2e1e7eb9bc291d4e70c993471d3c9ffa799
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.calendar.month;
18
19import com.android.calendar.Event;
20import com.android.calendar.R;
21import com.android.calendar.Utils;
22
23import android.content.Context;
24import android.content.res.Configuration;
25import android.content.res.Resources;
26import android.graphics.Canvas;
27import android.graphics.Paint;
28import android.graphics.Paint.Align;
29import android.graphics.Paint.Style;
30import android.graphics.Typeface;
31import android.graphics.drawable.Drawable;
32import android.text.TextPaint;
33import android.text.TextUtils;
34import android.text.format.DateUtils;
35import android.text.format.Time;
36import android.util.Log;
37
38import java.util.ArrayList;
39import java.util.Arrays;
40import java.util.Formatter;
41import java.util.HashMap;
42import java.util.Iterator;
43import java.util.List;
44import java.util.Locale;
45
46public class MonthWeekEventsView extends SimpleWeekView {
47    private static final String TAG = "MonthView";
48
49    public static final String VIEW_PARAMS_ORIENTATION = "orientation";
50
51    private static int TEXT_SIZE_MONTH_NUMBER = 32;
52    private static int TEXT_SIZE_EVENT = 14;
53    private static int TEXT_SIZE_MORE_EVENTS = 12;
54    private static int TEXT_SIZE_MONTH_NAME = 14;
55    private static int TEXT_SIZE_WEEK_NUM = 12;
56
57    private static final int DEFAULT_EDGE_SPACING = 4;
58    private static int PADDING_MONTH_NUMBER = 4;
59    private static int PADDING_WEEK_NUMBER = 16;
60    private static int DAY_SEPARATOR_OUTER_WIDTH = 5;
61    private static int DAY_SEPARATOR_INNER_WIDTH = 1;
62    private static int DAY_SEPARATOR_VERTICAL_LENGTH = 53;
63    private static int DAY_SEPARATOR_VERTICAL_LENGHT_PORTRAIT = 64;
64
65    private static int EVENT_X_OFFSET_LANDSCAPE = 44;
66    private static int EVENT_Y_OFFSET_LANDSCAPE = 11;
67    private static int EVENT_Y_OFFSET_PORTRAIT = 18;
68    private static int EVENT_SQUARE_WIDTH = 10;
69    private static int EVENT_SQUARE_BORDER = 1;
70    private static int EVENT_LINE_PADDING = 4;
71    private static int EVENT_RIGHT_PADDING = 4;
72    private static int EVENT_BOTTOM_PADDING = 15;
73
74    private static int SPACING_WEEK_NUMBER = 19;
75    private static boolean mScaled = false;
76
77    protected Time mToday = new Time();
78    protected boolean mHasToday = false;
79    protected int mTodayIndex = -1;
80    protected int mOrientation = Configuration.ORIENTATION_LANDSCAPE;
81    protected List<ArrayList<Event>> mEvents = null;
82    // This is for drawing the outlines around event chips and supports up to 10
83    // events being drawn on each day. The code will expand this if necessary.
84    protected FloatRef mEventOutlines = new FloatRef(10 * 4 * 4 * 7);
85
86    protected static StringBuilder mStringBuilder = new StringBuilder(50);
87    // TODO recreate formatter when locale changes
88    protected static Formatter mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
89
90    protected Paint mMonthNamePaint;
91    protected TextPaint mEventPaint;
92    protected TextPaint mEventExtrasPaint;
93    protected Paint mWeekNumPaint;
94
95    protected Drawable mTodayDrawable;
96
97    protected int mMonthNumHeight;
98    protected int mEventHeight;
99    protected int mExtrasHeight;
100    protected int mWeekNumHeight;
101
102    protected int mMonthNumColor;
103    protected int mMonthNumOtherColor;
104    protected int mMonthNumTodayColor;
105    protected int mMonthNameColor;
106    protected int mMonthNameOtherColor;
107    protected int mMonthEventColor;
108    protected int mMonthEventExtraColor;
109    protected int mMonthEventOtherColor;
110    protected int mMonthEventExtraOtherColor;
111    protected int mMonthWeekNumColor;
112
113    protected int mEventChipOutlineColor = 0xFFFFFFFF;
114    protected int mDaySeparatorOuterColor = 0x33FFFFFF;
115    protected int mDaySeparatorInnerColor = 0x1A000000;
116
117    /**
118     * This provides a reference to a float array which allows for easy size
119     * checking and reallocation. Used for drawing lines.
120     */
121    private class FloatRef {
122        float[] array;
123
124        public FloatRef(int size) {
125            array = new float[size];
126        }
127
128        public void ensureSize(int newSize) {
129            if (newSize >= array.length) {
130                // Add enough space for 7 more boxes to be drawn
131                array = Arrays.copyOf(array, newSize + 16 * 7);
132            }
133        }
134    }
135
136    /**
137     * @param context
138     */
139    public MonthWeekEventsView(Context context) {
140        super(context);
141
142        Resources resources = context.getResources();
143        TEXT_SIZE_MONTH_NUMBER = resources.getInteger(R.integer.text_size_month_number);
144
145        mPadding = DEFAULT_EDGE_SPACING;
146        if (mScale != 1 && !mScaled) {
147            PADDING_MONTH_NUMBER *= mScale;
148            PADDING_WEEK_NUMBER *= mScale;
149            SPACING_WEEK_NUMBER *= mScale;
150            TEXT_SIZE_MONTH_NUMBER *= mScale;
151            TEXT_SIZE_EVENT *= mScale;
152            TEXT_SIZE_MORE_EVENTS *= mScale;
153            TEXT_SIZE_MONTH_NAME *= mScale;
154            TEXT_SIZE_WEEK_NUM *= mScale;
155            DAY_SEPARATOR_OUTER_WIDTH *= mScale;
156            DAY_SEPARATOR_INNER_WIDTH *= mScale;
157            DAY_SEPARATOR_VERTICAL_LENGTH *= mScale;
158            DAY_SEPARATOR_VERTICAL_LENGHT_PORTRAIT *= mScale;
159            EVENT_X_OFFSET_LANDSCAPE *= mScale;
160            EVENT_Y_OFFSET_LANDSCAPE *= mScale;
161            EVENT_Y_OFFSET_PORTRAIT *= mScale;
162            EVENT_SQUARE_WIDTH *= mScale;
163            EVENT_LINE_PADDING *= mScale;
164            EVENT_BOTTOM_PADDING *= mScale;
165            EVENT_RIGHT_PADDING *= mScale;
166            mPadding = (int) (DEFAULT_EDGE_SPACING * mScale);
167            mScaled = true;
168        }
169    }
170
171    public void setEvents(List<ArrayList<Event>> sortedEvents) {
172        mEvents = sortedEvents;
173        if (sortedEvents == null) {
174            return;
175        }
176        if (sortedEvents.size() != mNumDays) {
177            if (Log.isLoggable(TAG, Log.ERROR)) {
178                Log.wtf(TAG, "Events size must be same as days displayed: size="
179                        + sortedEvents.size() + " days=" + mNumDays);
180            }
181            mEvents = null;
182            return;
183        }
184    }
185
186    protected void loadColors(Context context) {
187        Resources res = context.getResources();
188        mMonthWeekNumColor = res.getColor(R.color.month_week_num_color);
189        mMonthNumColor = res.getColor(R.color.month_day_number);
190        mMonthNumOtherColor = res.getColor(R.color.month_day_number_other);
191        mMonthNumTodayColor = res.getColor(R.color.month_today_number);
192        mMonthNameColor = mMonthNumColor;
193        mMonthNameOtherColor = mMonthNumOtherColor;
194        mMonthEventColor = res.getColor(R.color.month_event_color);
195        mMonthEventExtraColor = res.getColor(R.color.month_event_extra_color);
196        mMonthEventOtherColor = res.getColor(R.color.month_event_other_color);
197        mMonthEventExtraOtherColor = res.getColor(R.color.month_event_extra_other_color);
198
199        mTodayDrawable = res.getDrawable(R.drawable.today_blue_week_holo_light);
200    }
201
202    /**
203     * Sets up the text and style properties for painting. Override this if you
204     * want to use a different paint.
205     */
206    @Override
207    protected void setPaintProperties() {
208        loadColors(mContext);
209        // TODO modify paint properties depending on isMini
210        p.setStyle(Style.FILL);
211
212        mMonthNumPaint = new Paint();
213        mMonthNumPaint.setFakeBoldText(false);
214        mMonthNumPaint.setAntiAlias(true);
215        mMonthNumPaint.setTextSize(TEXT_SIZE_MONTH_NUMBER);
216        mMonthNumPaint.setColor(mMonthNumColor);
217        mMonthNumPaint.setStyle(Style.FILL);
218        mMonthNumPaint.setTextAlign(Align.LEFT);
219        mMonthNumPaint.setTypeface(Typeface.DEFAULT_BOLD);
220
221        mMonthNumHeight = (int) (-mMonthNumPaint.ascent());
222
223        mEventPaint = new TextPaint();
224        mEventPaint.setFakeBoldText(false);
225        mEventPaint.setAntiAlias(true);
226        mEventPaint.setTextSize(TEXT_SIZE_EVENT);
227        mEventPaint.setColor(mMonthEventColor);
228
229        mEventHeight = (int) (-mEventPaint.ascent());
230
231        mEventExtrasPaint = new TextPaint();
232        mEventExtrasPaint.setFakeBoldText(false);
233        mEventExtrasPaint.setAntiAlias(true);
234        mEventExtrasPaint.setStrokeWidth(EVENT_SQUARE_BORDER);
235        mEventExtrasPaint.setTextSize(TEXT_SIZE_EVENT);
236        mEventExtrasPaint.setColor(mMonthEventExtraColor);
237        mEventExtrasPaint.setStyle(Style.FILL);
238        mEventExtrasPaint.setTextAlign(Align.LEFT);
239
240        mWeekNumPaint = new Paint();
241        mWeekNumPaint.setFakeBoldText(false);
242        mWeekNumPaint.setAntiAlias(true);
243        mWeekNumPaint.setTextSize(TEXT_SIZE_WEEK_NUM);
244        mWeekNumPaint.setColor(mWeekNumColor);
245        mWeekNumPaint.setStyle(Style.FILL);
246        mWeekNumPaint.setTextAlign(Align.RIGHT);
247
248        mWeekNumHeight = (int) (-mWeekNumPaint.ascent());
249    }
250
251    @Override
252    public void setWeekParams(HashMap<String, Integer> params, String tz) {
253        super.setWeekParams(params, tz);
254
255        if (params.containsKey(VIEW_PARAMS_ORIENTATION)) {
256            mOrientation = params.get(VIEW_PARAMS_ORIENTATION);
257        }
258
259        mToday.timezone = tz;
260        mToday.setToNow();
261        mToday.normalize(true);
262        int julianToday = Time.getJulianDay(mToday.toMillis(false), mToday.gmtoff);
263        if (julianToday >= mFirstJulianDay && julianToday < mFirstJulianDay + mNumDays) {
264            mHasToday = true;
265            mTodayIndex = julianToday - mFirstJulianDay;
266        } else {
267            mHasToday = false;
268            mTodayIndex = -1;
269        }
270        mNumCells = mNumDays + 1;
271    }
272
273    @Override
274    protected void onDraw(Canvas canvas) {
275        drawBackground(canvas);
276        drawWeekNums(canvas);
277        drawDaySeparators(canvas);
278        drawEvents(canvas);
279    }
280
281    @Override
282    protected void drawDaySeparators(Canvas canvas) {
283        // mDaySeparatorOuterColor
284        float lines[] = new float[8 * 4];
285        int count = 7 * 4;
286        int wkNumOffset = 0;
287        int effectiveWidth = mWidth - mPadding * 2;
288        count += 4;
289        wkNumOffset = 1;
290        effectiveWidth -= SPACING_WEEK_NUMBER;
291        lines[0] = mPadding;
292        lines[1] = DAY_SEPARATOR_OUTER_WIDTH / 2 + 1;
293        lines[2] = mWidth - mPadding;
294        lines[3] = lines[1];
295        int y0 = DAY_SEPARATOR_OUTER_WIDTH / 2 + DAY_SEPARATOR_INNER_WIDTH;
296        int y1;
297        if (mOrientation == Configuration.ORIENTATION_PORTRAIT) {
298            y1 = y0 + DAY_SEPARATOR_VERTICAL_LENGHT_PORTRAIT;
299        } else {
300            y1 = y0 + DAY_SEPARATOR_VERTICAL_LENGTH;
301        }
302
303        for (int i = 4; i < count;) {
304            int x = (i / 4 - wkNumOffset) * effectiveWidth / (mNumDays) + mPadding
305                    + (SPACING_WEEK_NUMBER * wkNumOffset);
306            lines[i++] = x;
307            lines[i++] = y0;
308            lines[i++] = x;
309            lines[i++] = y1;
310        }
311        p.setColor(mDaySeparatorOuterColor);
312        p.setStrokeWidth(DAY_SEPARATOR_OUTER_WIDTH);
313        canvas.drawLines(lines, 0, count, p);
314        p.setColor(mDaySeparatorInnerColor);
315        p.setStrokeWidth(DAY_SEPARATOR_INNER_WIDTH);
316        canvas.drawLines(lines, 0, count, p);
317    }
318
319    @Override
320    protected void drawBackground(Canvas canvas) {
321        if (mHasToday) {
322            p.setColor(mSelectedWeekBGColor);
323        } else {
324            return;
325        }
326        int wkNumOffset = 0;
327        int effectiveWidth = mWidth - mPadding * 2;
328        wkNumOffset = 1;
329        effectiveWidth -= SPACING_WEEK_NUMBER;
330        r.top = DAY_SEPARATOR_OUTER_WIDTH + 1;
331        r.bottom = mHeight;
332        r.left = (mTodayIndex) * effectiveWidth / (mNumDays) + mPadding
333                + (SPACING_WEEK_NUMBER * wkNumOffset) + DAY_SEPARATOR_OUTER_WIDTH / 2 + 1;
334        r.right = (mTodayIndex + 1) * effectiveWidth / (mNumDays) + mPadding
335                + (SPACING_WEEK_NUMBER * wkNumOffset) - DAY_SEPARATOR_OUTER_WIDTH / 2;
336        mTodayDrawable.setBounds(r);
337        mTodayDrawable.draw(canvas);
338    }
339
340    @Override
341    protected void drawWeekNums(Canvas canvas) {
342        int y;
343
344        int i = 0;
345        int offset = 0;
346        int effectiveWidth = mWidth - mPadding * 2;
347        int todayIndex = mTodayIndex;
348        int x = PADDING_WEEK_NUMBER + mPadding;
349        int numCount = mNumDays;
350        y = mWeekNumHeight + PADDING_MONTH_NUMBER;
351        if (mShowWeekNum) {
352            canvas.drawText(mDayNumbers[0], x, y, mWeekNumPaint);
353            numCount++;
354            i++;
355            todayIndex++;
356            offset++;
357        }
358        effectiveWidth -= SPACING_WEEK_NUMBER;
359
360        y = (mMonthNumHeight + PADDING_MONTH_NUMBER);
361
362        boolean isFocusMonth = mFocusDay[i];
363        mMonthNumPaint.setColor(isFocusMonth ? mMonthNumColor : mMonthNumOtherColor);
364        for (; i < numCount; i++) {
365            if (mHasToday && todayIndex == i) {
366                mMonthNumPaint.setColor(mMonthNumTodayColor);
367                if (i + 1 < numCount) {
368                    // Make sure the color will be set back on the next
369                    // iteration
370                    isFocusMonth = !mFocusDay[i + 1];
371                }
372            } else if (mFocusDay[i] != isFocusMonth) {
373                isFocusMonth = mFocusDay[i];
374                mMonthNumPaint.setColor(isFocusMonth ? mMonthNumColor : mMonthNumOtherColor);
375            }
376            x = (i - offset) * effectiveWidth / (mNumDays) + mPadding + PADDING_MONTH_NUMBER
377                    + SPACING_WEEK_NUMBER;
378            canvas.drawText(mDayNumbers[i], x, y, mMonthNumPaint);
379
380        }
381    }
382
383    protected void drawEvents(Canvas canvas) {
384        if (mEvents == null) {
385            return;
386        }
387        int wkNumOffset = 0;
388        int effectiveWidth = mWidth - mPadding * 2;
389        wkNumOffset = 1;
390        effectiveWidth -= SPACING_WEEK_NUMBER;
391
392        int day = -1;
393        int outlineCount = 0;
394        for (ArrayList<Event> eventDay : mEvents) {
395            day++;
396            if (eventDay == null || eventDay.size() == 0) {
397                continue;
398            }
399            int ySquare;
400            int xSquare = day * effectiveWidth / (mNumDays) + mPadding
401                    + (SPACING_WEEK_NUMBER * wkNumOffset);
402            if (mOrientation == Configuration.ORIENTATION_PORTRAIT) {
403                ySquare = EVENT_Y_OFFSET_PORTRAIT + mMonthNumHeight + PADDING_MONTH_NUMBER;
404                xSquare += PADDING_MONTH_NUMBER + 1;
405            } else {
406                ySquare = EVENT_Y_OFFSET_LANDSCAPE;
407                xSquare += EVENT_X_OFFSET_LANDSCAPE;
408            }
409            int rightEdge = (day + 1) * effectiveWidth / (mNumDays) + mPadding
410                    + (SPACING_WEEK_NUMBER * wkNumOffset) - EVENT_RIGHT_PADDING;
411            int eventCount = 0;
412            Iterator<Event> iter = eventDay.iterator();
413            while (iter.hasNext()) {
414                Event event = iter.next();
415                int newY = drawEvent(canvas, event, xSquare, ySquare, rightEdge, iter.hasNext());
416                if (newY == ySquare) {
417                    break;
418                }
419                outlineCount = addChipOutline(mEventOutlines, outlineCount, xSquare, ySquare);
420                eventCount++;
421                ySquare = newY;
422            }
423
424            int remaining = eventDay.size() - eventCount;
425            if (remaining > 0) {
426                drawMoreEvents(canvas, remaining, xSquare);
427            }
428        }
429        if (outlineCount > 0) {
430            p.setColor(mEventChipOutlineColor);
431            p.setStrokeWidth(EVENT_SQUARE_BORDER);
432            canvas.drawLines(mEventOutlines.array, 0, outlineCount, p);
433        }
434    }
435
436    protected int addChipOutline(FloatRef lines, int count, int x, int y) {
437        lines.ensureSize(count + 16);
438        // top of box
439        lines.array[count++] = x;
440        lines.array[count++] = y;
441        lines.array[count++] = x + EVENT_SQUARE_WIDTH;
442        lines.array[count++] = y;
443        // right side of box
444        lines.array[count++] = x + EVENT_SQUARE_WIDTH;
445        lines.array[count++] = y;
446        lines.array[count++] = x + EVENT_SQUARE_WIDTH;
447        lines.array[count++] = y + EVENT_SQUARE_WIDTH;
448        // left side of box
449        lines.array[count++] = x;
450        lines.array[count++] = y;
451        lines.array[count++] = x;
452        lines.array[count++] = y + EVENT_SQUARE_WIDTH + 1;
453        // bottom of box
454        lines.array[count++] = x;
455        lines.array[count++] = y + EVENT_SQUARE_WIDTH;
456        lines.array[count++] = x + EVENT_SQUARE_WIDTH + 1;
457        lines.array[count++] = y + EVENT_SQUARE_WIDTH;
458
459        return count;
460    }
461
462    /**
463     * Attempts to draw the given event. Returns the y for the next event or the
464     * original y if the event will not fit. An event is considered to not fit
465     * if the event and its extras won't fit or if there are more events and the
466     * more events line would not fit after drawing this event.
467     *
468     * @param event the event to draw
469     * @param x the top left corner for this event's color chip
470     * @param y the top left corner for this event's color chip
471     * @return the y for the next event or the original y if it won't fit
472     */
473    protected int drawEvent(
474            Canvas canvas, Event event, int x, int y, int rightEdge, boolean moreEvents) {
475        int requiredSpace = EVENT_LINE_PADDING + mEventHeight;
476        int multiplier = 1;
477        if (moreEvents) {
478            multiplier++;
479        }
480        if (!event.allDay) {
481            multiplier++;
482        }
483        requiredSpace *= multiplier;
484        if (requiredSpace + y >= mHeight - EVENT_BOTTOM_PADDING) {
485            // Not enough space, return
486            return y;
487        }
488        r.left = x;
489        r.right = x + EVENT_SQUARE_WIDTH;
490        r.top = y;
491        r.bottom = y + EVENT_SQUARE_WIDTH;
492        p.setColor(event.color);
493        canvas.drawRect(r, p);
494
495        int textX = x + EVENT_SQUARE_WIDTH + EVENT_LINE_PADDING;
496        int textY = y + mEventHeight - EVENT_LINE_PADDING / 2;
497        float avail = rightEdge - textX;
498        CharSequence text = TextUtils.ellipsize(
499                event.title, mEventPaint, avail, TextUtils.TruncateAt.END);
500        canvas.drawText(text.toString(), textX, textY, mEventPaint);
501        if (!event.allDay) {
502            textY += mEventHeight + EVENT_LINE_PADDING;
503            mStringBuilder.setLength(0);
504            text = DateUtils.formatDateRange(mContext, mFormatter, event.startMillis,
505                    event.endMillis, DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL,
506                    Utils.getTimeZone(mContext, null)).toString();
507            text = TextUtils.ellipsize(text, mEventExtrasPaint, avail, TextUtils.TruncateAt.END);
508            canvas.drawText(text.toString(), textX, textY, mEventExtrasPaint);
509        }
510
511        return textY + EVENT_LINE_PADDING;
512    }
513
514    protected void drawMoreEvents(Canvas canvas, int remainingEvents, int x) {
515        FloatRef lines = new FloatRef(4 * 4);
516        int y = mHeight - EVENT_BOTTOM_PADDING + EVENT_LINE_PADDING / 2 - mEventHeight;
517        addChipOutline(lines, 0, x, y);
518        canvas.drawLines(lines.array, mEventExtrasPaint);
519        String text = mContext.getResources().getQuantityString(
520                R.plurals.month_more_events, remainingEvents);
521        y = mHeight - EVENT_BOTTOM_PADDING;
522        x += EVENT_SQUARE_WIDTH + EVENT_LINE_PADDING;
523        mEventExtrasPaint.setFakeBoldText(true);
524        canvas.drawText(String.format(text, remainingEvents), x, y, mEventExtrasPaint);
525        mEventExtrasPaint.setFakeBoldText(false);
526    }
527
528    @Override
529    protected void updateSelectionPositions() {
530        if (mHasSelectedDay) {
531            int selectedPosition = mSelectedDay - mWeekStart;
532            if (selectedPosition < 0) {
533                selectedPosition += 7;
534            }
535            int effectiveWidth = mWidth - mPadding * 2;
536            effectiveWidth -= SPACING_WEEK_NUMBER;
537            mSelectedLeft = selectedPosition * effectiveWidth / mNumDays + mPadding;
538            mSelectedRight = (selectedPosition + 1) * effectiveWidth / mNumDays + mPadding;
539            mSelectedLeft += SPACING_WEEK_NUMBER;
540            mSelectedRight += SPACING_WEEK_NUMBER;
541        }
542    }
543
544    @Override
545    public Time getDayFromLocation(float x) {
546        int dayStart = SPACING_WEEK_NUMBER + mPadding;
547        if (x < dayStart || x > mWidth - mPadding) {
548            return null;
549        }
550        // Selection is (x - start) / (pixels/day) == (x -s) * day / pixels
551        int dayPosition = (int) ((x - dayStart) * mNumDays / (mWidth - dayStart - mPadding));
552        int day = mFirstJulianDay + dayPosition;
553
554        Time time = new Time(mTimeZone);
555        if (mWeek == 0) {
556            // This week is weird...
557            if (day < Time.EPOCH_JULIAN_DAY) {
558                day++;
559            } else if (day == Time.EPOCH_JULIAN_DAY) {
560                time.set(1, 0, 1970);
561                time.normalize(true);
562                return time;
563            }
564        }
565
566        time.setJulianDay(day);
567        return time;
568    }
569
570}
571