diff --git a/geodepy/convert.py b/geodepy/convert.py
index ed91357..988581a 100755
--- a/geodepy/convert.py
+++ b/geodepy/convert.py
@@ -23,13 +23,33 @@ def hp2dec(hp):
 
 
 class DMSAngle(object):
-    def __init__(self, degree=0, minute=0, second=0):
-        self.degree = int(degree)
+    def __init__(self, degree=0, minute=0, second=0.0):
+        # Set sign of object based on sign of any variable
+        if degree == 0:
+            if str(degree)[0] == '-':
+                self.sign = -1
+            elif minute < 0:
+                self.sign = -1
+            elif second < 0:
+                self.sign = -1
+            else:
+                self.sign = 1
+        elif degree > 0:
+            self.sign = 1
+        else:  # degree < 0
+            self.sign = -1
+        self.degree = abs(int(degree))
         self.minute = abs(int(minute))
         self.second = abs(second)
 
     def __repr__(self):
-        return '{DMSAngle: ' + str(self.degree) + 'd ' + str(self.minute) + 'm ' + str(self.second) + 's}'
+        if self.sign == -1:
+            signsymbol = '-'
+        elif self.sign == 1:
+            signsymbol = '+'
+        else:
+            signsymbol = 'error'
+        return '{DMSAngle: ' + signsymbol + str(self.degree) + 'd ' + str(self.minute) + 'm ' + str(self.second) + 's}'
 
     def __add__(self, other):
         return dec2dms(self.dec() + other.dec())
@@ -56,13 +76,19 @@ class DMSAngle(object):
             raise TypeError('Multiply only defined between DMSAngle Object and Int or Float')
 
     def __truediv__(self, other):
-        return dec2dms(self.dec() / other)
+        try:
+            return dec2dms(self.dec() / other)
+        except TypeError:
+            raise TypeError('Division only defined between DMSAngle Object and Int or Float')
 
     def __abs__(self):
-        return DMSAngle(abs(self.degree), self.minute, self.second)
+        return DMSAngle(self.degree, self.minute, self.second)
 
     def __neg__(self):
-        return DMSAngle(-self.degree, self.minute, self.second)
+        if self.sign == 1:
+            return DMSAngle(-self.degree, -self.minute, -self.second)
+        else:  # sign == -1
+            return DMSAngle(self.degree, self.minute, self.second)
 
     def __eq__(self, other):
         return self.dec() == other.dec()
@@ -77,28 +103,43 @@ class DMSAngle(object):
         return self.dec() > other.dec()
 
     def dec(self):
-        if self.degree >= 0:
-            return self.degree + (self.minute / 60) + (self.second / 3600)
-        else:
-            return -(abs(self.degree) + (self.minute / 60) + (self.second / 3600))
+        return self.sign * (self.degree + (self.minute / 60) + (self.second / 3600))
 
     def hp(self):
-        if self.degree >= 0:
-            return self.degree + (self.minute / 100) + (self.second / 10000)
-        else:
-            return -(abs(self.degree) + (self.minute / 100) + (self.second / 10000))
+        return self.sign * (self.degree + (self.minute / 100) + (self.second / 10000))
 
     def ddm(self):
-        return DDMAngle(self.degree, self.minute + (self.second/60))
+        if self.sign == 1:
+            return DDMAngle(self.degree, self.minute + (self.second/60))
+        else:  # sign == -1
+            return -DDMAngle(self.degree, self.minute + (self.second/60))
 
 
 class DDMAngle(object):
-    def __init__(self, degree, minute):
-        self.degree = int(degree)
+    def __init__(self, degree=0, minute=0.0):
+        # Set sign of object based on sign of any variable
+        if degree == 0:
+            if str(degree)[0] == '-':
+                self.sign = -1
+            elif minute < 0:
+                self.sign = -1
+            else:
+                self.sign = 1
+        elif degree > 0:
+            self.sign = 1
+        else:  # degree < 0
+            self.sign = -1
+        self.degree = abs(int(degree))
         self.minute = abs(minute)
 
     def __repr__(self):
-        return '{DDMAngle: ' + str(self.degree) + 'd ' + str(self.minute) + 'm}'
+        if self.sign == -1:
+            signsymbol = '-'
+        elif self.sign == 1:
+            signsymbol = '+'
+        else:
+            signsymbol = 'error'
+        return '{DDMAngle: ' + signsymbol + str(self.degree) + 'd ' + str(self.minute) + 'm}'
 
     def __add__(self, other):
         return dec2ddm(self.dec() + other.dec())
@@ -119,13 +160,19 @@ class DDMAngle(object):
             raise TypeError('Multiply only defined between DMSAngle Object and Int or Float')
 
     def __truediv__(self, other):
-        return dec2ddm(self.dec() / other)
+        try:
+            return dec2ddm(self.dec() / other)
+        except TypeError:
+            raise TypeError('Division only defined between DMSAngle Object and Int or Float')
 
     def __abs__(self):
-        return DDMAngle(abs(self.degree), self.minute)
+        return DDMAngle(self.degree, self.minute)
 
     def __neg__(self):
-        return DDMAngle(-self.degree, self.minute)
+        if self.sign == 1:
+            return DDMAngle(-self.degree, -self.minute)
+        else:  # sign == -1
+            return DDMAngle(self.degree, self.minute)
 
     def __eq__(self, other):
         return self.dec() == other.dec()
@@ -140,21 +187,15 @@ class DDMAngle(object):
         return self.dec() > other.dec()
 
     def dec(self):
-        if self.degree >= 0:
-            return self.degree + (self.minute / 60)
-        else:
-            return -(abs(self.degree) + (self.minute / 60))
+        return self.sign * (self.degree + (self.minute / 60))
 
     def hp(self):
         minute_int, second = divmod(self.minute, 1)
-        if self.degree >= 0:
-            return self.degree + (minute_int / 100) + (second * 0.006)
-        else:
-            return -(abs(self.degree) + (minute_int / 100) + (second * 0.006))
+        return self.sign * (self.degree + (minute_int / 100) + (second * 0.006))
 
     def dms(self):
         minute_int, second = divmod(self.minute, 1)
-        return DMSAngle(self.degree, minute_int, second * 60)
+        return self.sign * DMSAngle(self.degree, minute_int, second * 60)
 
 
 def dec2dms(dec):

Integer Negative Zero issue in DMSAngle and DDMAngle classes
When entering the degree component of a DMSAngle(degree, minute, second) or DDMAngle(degree, minute) object, if the degree component is between -1 and 0 (i.e. DMSAngle(-0,12,14)) this will incorrectly convert this to a positive value. This is because python interprets the input '-0' as an int with value 0 and does not retain the sign of this variable.
diff --git a/geodepy/tests/test_convert.py b/geodepy/tests/test_convert.py
index ae8d265..b0cade3 100644
--- a/geodepy/tests/test_convert.py
+++ b/geodepy/tests/test_convert.py
@@ -3,17 +3,27 @@ from geodepy.convert import dec2hp, hp2dec, DMSAngle, DDMAngle, dec2dms, dec2ddm
 
 dec_ex = 123.74875
 dec_ex2 = 12.575
+dec_ex3 = -12.575
+dec_ex4 = 0.0525
+dec_ex5 = 0.005
+
 hp_ex = 123.44555
 hp_ex2 = 12.3430
 hp_ex3 = -12.3430
+hp_ex4 = 0.0309
+hp_ex5 = 0.0018
 
 dms_ex = DMSAngle(123, 44, 55.5)
 dms_ex2 = DMSAngle(12, 34, 30)
 dms_ex3 = DMSAngle(-12, -34, -30)
+dms_ex4 = DMSAngle(0, 3, 9)
+dms_ex5 = DMSAngle(0, 0, 18)
 
 ddm_ex = DDMAngle(123, 44.925)
 ddm_ex2 = DDMAngle(12, 34.5)
 ddm_ex3 = DDMAngle(-12, -34.5)
+ddm_ex4 = DDMAngle(0, 3.15)
+ddm_ex5 = DDMAngle(0, 0.3)
 
 
 class TestConvert(unittest.TestCase):
@@ -33,6 +43,27 @@ class TestConvert(unittest.TestCase):
         self.assertEqual(hp_ex3, dms_ex3.hp())
         self.assertEqual(ddm_ex, dms_ex.ddm())
 
+        # Test DMSAngle Sign Conventions
+        self.assertEqual(-dec_ex, DMSAngle(-dms_ex.degree, dms_ex.minute, dms_ex.second).dec())
+        self.assertEqual(dec_ex, DMSAngle(dms_ex.degree, -dms_ex.minute, -dms_ex.second).dec())
+        self.assertAlmostEqual(-dec_ex4, DMSAngle(0, -dms_ex4.minute, dms_ex4.second).dec(), 9)
+        self.assertAlmostEqual(dec_ex4, DMSAngle(0, dms_ex4.minute, dms_ex4.second).dec(), 9)
+        self.assertEqual(-dec_ex5, DMSAngle(0, 0, -dms_ex5.second).dec())
+        self.assertEqual(dec_ex5, DMSAngle(0, 0, dms_ex5.second).dec())
+        self.assertEqual(dms_ex.sign, 1)
+        self.assertEqual(-dms_ex.sign, -1)
+        self.assertEqual(dms_ex4.sign, 1)
+        self.assertEqual(-dms_ex4.sign, -1)
+        self.assertEqual(dms_ex5.sign, 1)
+        self.assertEqual(-dms_ex5.sign, -1)
+        self.assertEqual(DMSAngle(-1, 2, 3).sign, -1)
+        self.assertEqual(DMSAngle(1, -2, 3).sign, 1)
+        self.assertEqual(DMSAngle(1, 2, -3).sign, 1)
+        self.assertEqual(DMSAngle(0, -1, 2).sign, -1)
+        self.assertEqual(DMSAngle(0, 0, -3).sign, -1)
+        self.assertEqual(DMSAngle(-0, 1, 2).sign, 1)
+        self.assertEqual(DMSAngle(-0.0, 1, 2).sign, -1)
+
         # Test DMSAngle Overloads
         self.assertEqual(dec_ex + dec_ex2, (dms_ex + dms_ex2).dec())
         self.assertEqual(dec_ex - dec_ex2, (dms_ex - dms_ex2).dec())
@@ -55,6 +86,8 @@ class TestConvert(unittest.TestCase):
             dms_ex * 'a'
         with self.assertRaises(TypeError):
             'a' * dms_ex
+        with self.assertRaises(TypeError):
+            dms_ex / 'a'
 
     def test_DDMAngle(self):
         # Test DDMAngle Methods
@@ -63,6 +96,24 @@ class TestConvert(unittest.TestCase):
         self.assertEqual(dms_ex, ddm_ex.dms())
         self.assertEqual(hp_ex3, ddm_ex3.hp())
 
+        # Test DMSAngle Sign Conventions
+        self.assertEqual(-dec_ex, DDMAngle(-dms_ex.degree, ddm_ex.minute).dec())
+        self.assertEqual(dec_ex, DDMAngle(dms_ex.degree, -ddm_ex.minute).dec())
+        self.assertAlmostEqual(-dec_ex4, DDMAngle(0, -ddm_ex4.minute).dec(), 9)
+        self.assertAlmostEqual(dec_ex4, DDMAngle(0, ddm_ex4.minute).dec(), 9)
+        self.assertEqual(ddm_ex.sign, 1)
+        self.assertEqual(-ddm_ex.sign, -1)
+        self.assertEqual(ddm_ex4.sign, 1)
+        self.assertEqual(-ddm_ex4.sign, -1)
+        self.assertEqual(ddm_ex5.sign, 1)
+        self.assertEqual(-ddm_ex5.sign, -1)
+        self.assertEqual(DDMAngle(-1, 2).sign, -1)
+        self.assertEqual(DDMAngle(1, -2).sign, 1)
+        self.assertEqual(DDMAngle(1, 2).sign, 1)
+        self.assertEqual(DDMAngle(0, -1).sign, -1)
+        self.assertEqual(DDMAngle(-0, 1).sign, 1)
+        self.assertEqual(DDMAngle(-0.0, 1).sign, -1)
+
         # Test DDMAngle Overloads
         self.assertEqual(dec_ex + dec_ex2, (ddm_ex + ddm_ex2).dec())
         self.assertEqual(dec_ex - dec_ex2, (ddm_ex - ddm_ex2).dec())
@@ -85,6 +136,8 @@ class TestConvert(unittest.TestCase):
             ddm_ex * 'a'
         with self.assertRaises(TypeError):
             'a' * ddm_ex
+        with self.assertRaises(TypeError):
+            ddm_ex / 'a'
 
     def test_dec2dms(self):
         self.assertEqual(dms_ex, dec2dms(dec_ex))
@@ -99,7 +152,8 @@ class TestConvert(unittest.TestCase):
         self.assertEqual(dms_ex.minute, hp2dms(hp_ex).minute)
         self.assertAlmostEqual(dms_ex.second, hp2dms(hp_ex).second, 10)
 
-        self.assertEqual(-dms_ex.degree, hp2dms(-hp_ex).degree)
+        self.assertEqual(-dms_ex.sign, hp2dms(-hp_ex).sign)
+        self.assertEqual(dms_ex.degree, hp2dms(-hp_ex).degree)
         self.assertEqual(dms_ex.minute, hp2dms(-hp_ex).minute)
         self.assertAlmostEqual(dms_ex.second, hp2dms(-hp_ex).second, 10)
 

pip install -e .
parse_log_pytest
requirements.txt
numpy>=1.16.0 pytest pytest-cov
apt-get update apt-get install -y gcc
3.9
api/requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
argcomplete==3.6.1
blinker==1.9.0
boto3==1.37.23
botocore==1.37.23
certifi==2025.1.31
cfn-flip==1.3.0
charset-normalizer==3.4.1
click==8.1.8
coverage==7.8.0
durationpy==0.9
exceptiongroup==1.2.2
Flask==3.1.0
-e git+https://github.com/GeoscienceAustralia/GeodePy.git@3c1531ecbca268ea1cf720854685917726670b63#egg=geodepy
hjson==3.1.0
idna==3.10
importlib_metadata==8.6.1
iniconfig==2.1.0
itsdangerous==2.2.0
Jinja2==3.1.6
jmespath==1.0.1
kappa==0.6.0
MarkupSafe==3.0.2
numpy==2.0.2
packaging==24.2
placebo==0.9.0
pluggy==1.5.0
pytest==8.3.5
pytest-cov==6.0.0
python-dateutil==2.9.0.post0
python-slugify==8.0.4
PyYAML==6.0.2
requests==2.32.3
s3transfer==0.11.4
scipy==1.13.1
six==1.17.0
text-unidecode==1.3
toml==0.10.2
tomli==2.2.1
tqdm==4.67.1
troposphere==4.9.0
urllib3==1.26.20
Werkzeug==3.1.3
zappa==0.59.0
zipp==3.21.0

name: GeodePy
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - argcomplete==3.6.1
      - blinker==1.9.0
      - boto3==1.37.23
      - botocore==1.37.23
      - certifi==2025.1.31
      - cfn-flip==1.3.0
      - charset-normalizer==3.4.1
      - click==8.1.8
      - coverage==7.8.0
      - durationpy==0.9
      - exceptiongroup==1.2.2
      - flask==3.1.0
      - hjson==3.1.0
      - idna==3.10
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - itsdangerous==2.2.0
      - jinja2==3.1.6
      - jmespath==1.0.1
      - kappa==0.6.0
      - markupsafe==3.0.2
      - numpy==2.0.2
      - packaging==24.2
      - placebo==0.9.0
      - pluggy==1.5.0
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - python-dateutil==2.9.0.post0
      - python-slugify==8.0.4
      - pyyaml==6.0.2
      - requests==2.32.3
      - s3transfer==0.11.4
      - scipy==1.13.1
      - six==1.17.0
      - text-unidecode==1.3
      - toml==0.10.2
      - tomli==2.2.1
      - tqdm==4.67.1
      - troposphere==4.9.0
      - urllib3==1.26.20
      - werkzeug==3.1.3
      - zappa==0.59.0
      - zipp==3.21.0
prefix: /opt/conda/envs/GeodePy

geodepy/tests/test_convert.py::TestConvert::test_DDMAngle geodepy/tests/test_convert.py::TestConvert::test_DMSAngle geodepy/tests/test_convert.py::TestConvert::test_hp2dms
geodepy/tests/test_convert.py::TestConvert::test_dd2dms geodepy/tests/test_convert.py::TestConvert::test_dec2ddm geodepy/tests/test_convert.py::TestConvert::test_dec2dms geodepy/tests/test_convert.py::TestConvert::test_dec2hp geodepy/tests/test_convert.py::TestConvert::test_hp2ddm geodepy/tests/test_convert.py::TestConvert::test_hp2dec
geodepy/convert.py
geodepy/convert.py