DayAxisValueFormatter.swift 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. //
  2. // DayAxisValueFormatter.swift
  3. // ChartsDemo-iOS
  4. //
  5. // Created by Jacob Christie on 2017-07-09.
  6. // Copyright © 2017 jc. All rights reserved.
  7. //
  8. import Foundation
  9. import Charts
  10. public class DayAxisValueFormatter: NSObject, AxisValueFormatter {
  11. weak var chart: BarLineChartViewBase?
  12. let months = ["Jan", "Feb", "Mar",
  13. "Apr", "May", "Jun",
  14. "Jul", "Aug", "Sep",
  15. "Oct", "Nov", "Dec"]
  16. init(chart: BarLineChartViewBase) {
  17. self.chart = chart
  18. }
  19. public func stringForValue(_ value: Double, axis: AxisBase?) -> String {
  20. let days = Int(value)
  21. let year = determineYear(forDays: days)
  22. let month = determineMonth(forDayOfYear: days)
  23. let monthName = months[month % months.count]
  24. let yearName = "\(year)"
  25. if let chart = chart,
  26. chart.visibleXRange > 30 * 6 {
  27. return monthName + yearName
  28. } else {
  29. let dayOfMonth = determineDayOfMonth(forDays: days, month: month + 12 * (year - 2016))
  30. var appendix: String
  31. switch dayOfMonth {
  32. case 1, 21, 31: appendix = "st"
  33. case 2, 22: appendix = "nd"
  34. case 3, 23: appendix = "rd"
  35. default: appendix = "th"
  36. }
  37. return dayOfMonth == 0 ? "" : String(format: "%d\(appendix) \(monthName)", dayOfMonth)
  38. }
  39. }
  40. private func days(forMonth month: Int, year: Int) -> Int {
  41. // month is 0-based
  42. switch month {
  43. case 1:
  44. var is29Feb = false
  45. if year < 1582 {
  46. is29Feb = (year < 1 ? year + 1 : year) % 4 == 0
  47. } else if year > 1582 {
  48. is29Feb = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
  49. }
  50. return is29Feb ? 29 : 28
  51. case 3, 5, 8, 10:
  52. return 30
  53. default:
  54. return 31
  55. }
  56. }
  57. private func determineMonth(forDayOfYear dayOfYear: Int) -> Int {
  58. var month = -1
  59. var days = 0
  60. while days < dayOfYear {
  61. month += 1
  62. if month >= 12 {
  63. month = 0
  64. }
  65. let year = determineYear(forDays: days)
  66. days += self.days(forMonth: month, year: year)
  67. }
  68. return max(month, 0)
  69. }
  70. private func determineDayOfMonth(forDays days: Int, month: Int) -> Int {
  71. var count = 0
  72. var daysForMonth = 0
  73. while count < month {
  74. let year = determineYear(forDays: days)
  75. daysForMonth += self.days(forMonth: count % 12, year: year)
  76. count += 1
  77. }
  78. return days - daysForMonth
  79. }
  80. private func determineYear(forDays days: Int) -> Int {
  81. switch days {
  82. case ...366: return 2016
  83. case 367...730: return 2017
  84. case 731...1094: return 2018
  85. case 1095...1458: return 2019
  86. default: return 2020
  87. }
  88. }
  89. }