1 /*
2  * Copyright (C) 2015 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 
17 package com.android.tools.build.apkzlib.zip.utils;
18 
19 import com.google.common.base.Verify;
20 import java.util.Calendar;
21 import java.util.Date;
22 
23 /**
24  * Yes. This actually refers to MS-DOS in 2015. That's all I have to say about legacy stuff.
25  */
26 public class MsDosDateTimeUtils {
27     /**
28      * Utility class: no constructor.
29      */
MsDosDateTimeUtils()30     private MsDosDateTimeUtils() {
31     }
32 
33     /**
34      * Packs java time value into an MS-DOS time value.
35      *
36      * @param time the time value
37      * @return the MS-DOS packed time
38      */
packTime(long time)39     public static int packTime(long time) {
40         Calendar c = Calendar.getInstance();
41         c.setTime(new Date(time));
42 
43         int seconds = c.get(Calendar.SECOND);
44         int minutes = c.get(Calendar.MINUTE);
45         int hours = c.get(Calendar.HOUR_OF_DAY);
46 
47         /*
48          * Here is how MS-DOS packs a time value:
49          * 0-4: seconds (divided by 2 because we only have 5 bits = 32 different numbers)
50          * 5-10: minutes (6 bits = 64 possible values)
51          * 11-15: hours (5 bits = 32 possible values)
52          *
53          * source: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724247(v=vs.85).aspx
54          */
55         return (hours << 11) | (minutes << 5) | (seconds / 2);
56     }
57 
58     /**
59      * Packs the current time value into an MS-DOS time value.
60      *
61      * @return the MS-DOS packed time
62      */
packCurrentTime()63     public static int packCurrentTime() {
64         return packTime(new Date().getTime());
65     }
66 
67     /**
68      * Packs java time value into an MS-DOS date value.
69      *
70      * @param time the time value
71      * @return the MS-DOS packed date
72      */
packDate(long time)73     public static int packDate(long time) {
74         Calendar c = Calendar.getInstance();
75         c.setTime(new Date(time));
76 
77         /*
78          * Even MS-DOS used 1 for January. Someone wasn't really thinking when they decided on Java
79          * it would start at 0...
80          */
81         int day = c.get(Calendar.DAY_OF_MONTH);
82         int month = c.get(Calendar.MONTH) + 1;
83 
84         /*
85          * MS-DOS counts years starting from 1980. Since its launch date was in 81, it was obviously
86          * not necessary to talk about dates earlier than that.
87          */
88         int year = c.get(Calendar.YEAR) - 1980;
89         Verify.verify(year >= 0 && year < 128);
90 
91         /*
92          * Here is how MS-DOS packs a date value:
93          * 0-4: day (5 bits = 32 values)
94          * 5-8: month (4 bits = 16 values)
95          * 9-15: year (7 bits = 128 values)
96          *
97          * source: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724247(v=vs.85).aspx
98          */
99         return (year << 9) | (month << 5) | day;
100     }
101 
102     /**
103      * Packs the current time value into an MS-DOS date value.
104      *
105      * @return the MS-DOS packed date
106      */
packCurrentDate()107     public static int packCurrentDate() {
108         return packDate(new Date().getTime());
109     }
110 }
111