HabitBullCSVImporter: Accept multiple date formats

Fixes 762
pull/794/head
Alinson S. Xavier 5 years ago
parent c53997ffcc
commit b58af03a7c

@ -0,0 +1,82 @@
HabitName,HabitDescription,HabitCategory,CalendarDate,Value,CommentText
H1,,C1,11/5/2020,1,
H2,,C2,11/5/2020,-2150000000,
H3,Habit 3,C3,4/11/2019,1,
H3,Habit 3,C3,4/12/2019,1,
H3,Habit 3,C3,4/13/2019,0,
H3,Habit 3,C3,4/14/2019,1,
H3,Habit 3,C3,4/15/2019,1,
H3,Habit 3,C3,4/16/2019,1,
H3,Habit 3,C3,4/17/2019,1,
H3,Habit 3,C3,4/18/2019,1,
H3,Habit 3,C3,4/19/2019,0,
H3,Habit 3,C3,4/20/2019,1,
H3,Habit 3,C3,4/21/2019,1,
H3,Habit 3,C3,4/22/2019,1,
H3,Habit 3,C3,4/23/2019,0,
H3,Habit 3,C3,4/24/2019,1,
H3,Habit 3,C3,4/25/2019,1,
H3,Habit 3,C3,4/26/2019,1,
H3,Habit 3,C3,4/27/2019,0,
H3,Habit 3,C3,4/28/2019,1,
H3,Habit 3,C3,4/29/2019,0,
H3,Habit 3,C3,4/30/2019,1,
H3,Habit 3,C3,5/1/2019,1,
H3,Habit 3,C3,5/2/2019,1,
H3,Habit 3,C3,5/3/2019,1,
H3,Habit 3,C3,5/4/2019,1,
H3,Habit 3,C3,5/5/2019,1,
H3,Habit 3,C3,5/6/2019,0,
H3,Habit 3,C3,5/7/2019,1,
H3,Habit 3,C3,5/8/2019,1,
H3,Habit 3,C3,5/9/2019,1,
H3,Habit 3,C3,5/10/2019,1,
H3,Habit 3,C3,5/11/2019,1,
H3,Habit 3,C3,5/12/2019,1,
H3,Habit 3,C3,5/13/2019,1,
H3,Habit 3,C3,5/14/2019,1,
H3,Habit 3,C3,5/15/2019,1,
H3,Habit 3,C3,5/16/2019,1,
H3,Habit 3,C3,5/17/2019,1,
H3,Habit 3,C3,5/18/2019,0,
H3,Habit 3,C3,5/19/2019,1,
H3,Habit 3,C3,5/20/2019,1,
H3,Habit 3,C3,5/21/2019,1,
H3,Habit 3,C3,5/22/2019,1,
H3,Habit 3,C3,5/23/2019,1,
H3,Habit 3,C3,5/24/2019,1,
H3,Habit 3,C3,5/25/2019,1,
H3,Habit 3,C3,5/26/2019,1,
H3,Habit 3,C3,5/27/2019,1,
H3,Habit 3,C3,5/28/2019,1,
H3,Habit 3,C3,5/29/2019,1,
H3,Habit 3,C3,5/30/2019,0,
H3,Habit 3,C3,5/31/2019,1,
H3,Habit 3,C3,6/1/2019,1,
H3,Habit 3,C3,6/2/2019,1,
H3,Habit 3,C3,6/3/2019,1,
H3,Habit 3,C3,6/4/2019,1,
H3,Habit 3,C3,6/5/2019,1,
H3,Habit 3,C3,6/6/2019,1,
H3,Habit 3,C3,6/7/2019,1,
H3,Habit 3,C3,6/8/2019,1,
H3,Habit 3,C3,6/9/2019,1,
H3,Habit 3,C3,6/10/2019,1,
H3,Habit 3,C3,6/11/2019,1,
H3,Habit 3,C3,6/12/2019,1,
H3,Habit 3,C3,6/13/2019,1,
H3,Habit 3,C3,6/14/2019,0,
H3,Habit 3,C3,6/15/2019,1,
H4,Habit 4,C4,11/6/2020,1,
H4,Habit 4,C4,11/9/2020,1,
H4,Habit 4,C4,11/11/2020,1,
H4,Habit 4,C4,12/30/2020,-2150000000,
H5,Habit 5,C4,11/5/2020,1,
H5,Habit 5,C4,11/6/2020,1,
H5,Habit 5,C4,11/9/2020,1,
H5,Habit 5,C4,11/11/2020,1,
H6,Habit 6,C5,11/5/2020,1,
H6,Habit 6,C5,11/6/2020,1,
H6,Habit 6,C5,11/9/2020,1,
H6,Habit 6,C5,11/11/2020,1,
H6,Habit 6,C5,11/12/2020,1,
1 HabitName HabitDescription HabitCategory CalendarDate Value CommentText
2 H1 C1 11/5/2020 1
3 H2 C2 11/5/2020 -2150000000
4 H3 Habit 3 C3 4/11/2019 1
5 H3 Habit 3 C3 4/12/2019 1
6 H3 Habit 3 C3 4/13/2019 0
7 H3 Habit 3 C3 4/14/2019 1
8 H3 Habit 3 C3 4/15/2019 1
9 H3 Habit 3 C3 4/16/2019 1
10 H3 Habit 3 C3 4/17/2019 1
11 H3 Habit 3 C3 4/18/2019 1
12 H3 Habit 3 C3 4/19/2019 0
13 H3 Habit 3 C3 4/20/2019 1
14 H3 Habit 3 C3 4/21/2019 1
15 H3 Habit 3 C3 4/22/2019 1
16 H3 Habit 3 C3 4/23/2019 0
17 H3 Habit 3 C3 4/24/2019 1
18 H3 Habit 3 C3 4/25/2019 1
19 H3 Habit 3 C3 4/26/2019 1
20 H3 Habit 3 C3 4/27/2019 0
21 H3 Habit 3 C3 4/28/2019 1
22 H3 Habit 3 C3 4/29/2019 0
23 H3 Habit 3 C3 4/30/2019 1
24 H3 Habit 3 C3 5/1/2019 1
25 H3 Habit 3 C3 5/2/2019 1
26 H3 Habit 3 C3 5/3/2019 1
27 H3 Habit 3 C3 5/4/2019 1
28 H3 Habit 3 C3 5/5/2019 1
29 H3 Habit 3 C3 5/6/2019 0
30 H3 Habit 3 C3 5/7/2019 1
31 H3 Habit 3 C3 5/8/2019 1
32 H3 Habit 3 C3 5/9/2019 1
33 H3 Habit 3 C3 5/10/2019 1
34 H3 Habit 3 C3 5/11/2019 1
35 H3 Habit 3 C3 5/12/2019 1
36 H3 Habit 3 C3 5/13/2019 1
37 H3 Habit 3 C3 5/14/2019 1
38 H3 Habit 3 C3 5/15/2019 1
39 H3 Habit 3 C3 5/16/2019 1
40 H3 Habit 3 C3 5/17/2019 1
41 H3 Habit 3 C3 5/18/2019 0
42 H3 Habit 3 C3 5/19/2019 1
43 H3 Habit 3 C3 5/20/2019 1
44 H3 Habit 3 C3 5/21/2019 1
45 H3 Habit 3 C3 5/22/2019 1
46 H3 Habit 3 C3 5/23/2019 1
47 H3 Habit 3 C3 5/24/2019 1
48 H3 Habit 3 C3 5/25/2019 1
49 H3 Habit 3 C3 5/26/2019 1
50 H3 Habit 3 C3 5/27/2019 1
51 H3 Habit 3 C3 5/28/2019 1
52 H3 Habit 3 C3 5/29/2019 1
53 H3 Habit 3 C3 5/30/2019 0
54 H3 Habit 3 C3 5/31/2019 1
55 H3 Habit 3 C3 6/1/2019 1
56 H3 Habit 3 C3 6/2/2019 1
57 H3 Habit 3 C3 6/3/2019 1
58 H3 Habit 3 C3 6/4/2019 1
59 H3 Habit 3 C3 6/5/2019 1
60 H3 Habit 3 C3 6/6/2019 1
61 H3 Habit 3 C3 6/7/2019 1
62 H3 Habit 3 C3 6/8/2019 1
63 H3 Habit 3 C3 6/9/2019 1
64 H3 Habit 3 C3 6/10/2019 1
65 H3 Habit 3 C3 6/11/2019 1
66 H3 Habit 3 C3 6/12/2019 1
67 H3 Habit 3 C3 6/13/2019 1
68 H3 Habit 3 C3 6/14/2019 0
69 H3 Habit 3 C3 6/15/2019 1
70 H4 Habit 4 C4 11/6/2020 1
71 H4 Habit 4 C4 11/9/2020 1
72 H4 Habit 4 C4 11/11/2020 1
73 H4 Habit 4 C4 12/30/2020 -2150000000
74 H5 Habit 5 C4 11/5/2020 1
75 H5 Habit 5 C4 11/6/2020 1
76 H5 Habit 5 C4 11/9/2020 1
77 H5 Habit 5 C4 11/11/2020 1
78 H6 Habit 6 C5 11/5/2020 1
79 H6 Habit 6 C5 11/6/2020 1
80 H6 Habit 6 C5 11/9/2020 1
81 H6 Habit 6 C5 11/11/2020 1
82 H6 Habit 6 C5 11/12/2020 1

@ -25,11 +25,19 @@ import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.ModelFactory
import org.isoron.uhabits.core.models.Timestamp
import org.isoron.uhabits.core.utils.DateUtils
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
import java.text.DateFormat
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar.DAY_OF_MONTH
import java.util.Calendar.MONTH
import java.util.Calendar.YEAR
import java.util.Date
import java.util.GregorianCalendar
import java.util.HashMap
import java.util.Locale
import javax.inject.Inject
/**
@ -39,8 +47,11 @@ class HabitBullCSVImporter
@Inject constructor(
private val habitList: HabitList,
private val modelFactory: ModelFactory,
logging: Logging,
) : AbstractImporter() {
val logger = logging.getLogger("HabitBullCSVImporter")
override fun canHandle(file: File): Boolean {
val reader = BufferedReader(FileReader(file))
val line = reader.readLine()
@ -50,19 +61,11 @@ class HabitBullCSVImporter
override fun importHabitsFromFile(file: File) {
val reader = CSVReader(FileReader(file))
val map = HashMap<String, Habit>()
for (line in reader) {
val name = line[0]
for (cols in reader) {
val name = cols[0]
if (name == "HabitName") continue
val description = line[1]
val dateString = line[3].split("-").toTypedArray()
val year = dateString[0].toInt()
val month = dateString[1].toInt()
val day = dateString[2].toInt()
val date = DateUtils.getStartOfTodayCalendar()
date[year, month - 1] = day
val timestamp = Timestamp(date.timeInMillis)
val value = line[4].toInt()
if (value != 1) continue
val description = cols[1]
val timestamp = parseTimestamp(cols[3])
var h = map[name]
if (h == null) {
h = modelFactory.buildHabit()
@ -71,8 +74,46 @@ class HabitBullCSVImporter
h.frequency = Frequency.DAILY
habitList.add(h)
map[name] = h
logger.info("Creating habit: $name")
}
if (parseInt(cols[4]) == 1) {
h.originalEntries.add(Entry(timestamp, Entry.YES_MANUAL))
}
}
}
private fun parseTimestamp(rawValue: String): Timestamp {
val formats = listOf(
DateFormat.getDateInstance(DateFormat.SHORT),
SimpleDateFormat("yyyy-MM-dd", Locale.US),
SimpleDateFormat("MM/dd/yyyy", Locale.US),
)
var parsedDate: Date? = null
for (fmt in formats) {
try {
parsedDate = fmt.parse(rawValue)
} catch (e: ParseException) {
// ignored
}
}
if (parsedDate == null) {
throw Exception("Unrecognized date format: $rawValue")
}
val parsedCalendar = GregorianCalendar()
parsedCalendar.time = parsedDate
return Timestamp.from(
parsedCalendar[YEAR],
parsedCalendar[MONTH],
parsedCalendar[DAY_OF_MONTH],
)
}
private fun parseInt(rawValue: String): Int {
return try {
rawValue.toInt()
} catch (e: NumberFormatException) {
logger.error("Could not parse int: $rawValue. Replacing by zero.")
0
}
}
}

@ -56,6 +56,20 @@ class ImportTest : BaseUnitTest() {
assertFalse(isChecked(habit, 2016, 3, 20))
}
@Test
@Throws(IOException::class)
fun testHabitBullCSV2() {
importFromFile("habitbull2.csv")
assertThat(habitList.size(), equalTo(6))
val habit = habitList.getByPosition(2)
assertThat(habit.name, equalTo("H3"))
assertThat(habit.description, equalTo("Habit 3"))
assertThat(habit.frequency, equalTo(Frequency.DAILY))
assertTrue(isChecked(habit, 2019, 4, 11))
assertTrue(isChecked(habit, 2019, 5, 7))
assertFalse(isChecked(habit, 2019, 6, 14))
}
@Test
@Throws(IOException::class)
fun testLoopDB() {
@ -129,7 +143,7 @@ class ImportTest : BaseUnitTest() {
),
RewireDBImporter(habitList, modelFactory, databaseOpener),
TickmateDBImporter(habitList, modelFactory, databaseOpener),
HabitBullCSVImporter(habitList, modelFactory)
HabitBullCSVImporter(habitList, modelFactory, StandardLogging())
)
assertTrue(importer.canHandle(file))
importer.importHabitsFromFile(file)

Loading…
Cancel
Save